<!DOCTYPE html>
<html lang="zh-cn">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <meta http-equiv="X-UA-Compatible" content="IE=Edge,chrome=1">
  <meta name="theme-color" content="#3367D6"/>
  <link rel="apple-touch-icon" href="/icons-192.png">
  <link rel="manifest" href="/manifest.json">
  <link rel="stylesheet" href="/lib/google-code-prettify/themes/tomorrow-night.css">
  <script type="text/javascript" src="/lib/google-code-prettify/src/prettify.js"></script>
  
  <meta name="generator" content="Hexo 5.4.2">

  
    <meta name="description" content="觉宇宙之无穷，识盈虚之有数">
  

  

  
    <meta name="author" content="RocPengHua">
  

  

  

  <title>java并发 | 小鹏驿站</title>

  

  
    <link rel="shortcut icon" href="/favicon.ico">
  

  

  
<link rel="stylesheet" href="/css/style.css">

</head>
<body onload="PR.prettyPrint()">
  <div class="root-container">
    
<!-- header container -->
<header class="header-container post">
  
    <div class="post-image" style="background-image: url(&#39;https://api.lixingyong.com/api/images?postid=ded47261&amp;type=url&amp;itype=image&#39;)"></div>
  
  <!-- navbar -->
<nav class="navbar">
  <div class="navbar-content">
    <!-- logo -->
    <div class="navbar-logo">
      <a href="/">
        
          小鹏驿站
        
      </a>
    </div>
    <!-- link -->
    <div class="navbar-link">
      <div class="navbar-btn">
        <div></div>
        <div></div>
        <div></div>
      </div>
      <ul class="navbar-list">
        
              <li class="navbar-list-item">
                <a href="/">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-home faa-shake" aria-hidden="true"></i>
                    首页
                  </span>
                </a>
                
              </li>
            
              <li class="navbar-list-item">
                <a href="/archives">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-archive faa-shake" aria-hidden="true"></i>
                    归档
                  </span>
                </a>
                
              </li>
            
              <li class="navbar-list-item">
                <a href="/categories">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-folder faa-shake" aria-hidden="true"></i>
                    分类
                  </span>
                </a>
                
                  <ul class="sub-menu">
                    
                      <li>
                        <a href="/categories/%E5%90%8E%E7%AB%AF/">
                          <i class="fa fa-etsy" aria-hidden="true"></i>
                          后端
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E5%89%8D%E7%AB%AF/">
                          <i class="fa fa-grav" aria-hidden="true"></i>
                          前端
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E8%BD%AF%E4%BB%B6/">
                          <i class="fa fa-key" aria-hidden="true"></i>
                          软件
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E7%AE%97%E6%B3%95/">
                          <i class="fa fa-glass" aria-hidden="true"></i>
                          算法
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E6%95%B0%E6%8D%AE%E5%BA%93/">
                          <i class="fa fa-database" aria-hidden="true"></i>
                          数据库
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/">
                          <i class="fa fa-arrows-alt" aria-hidden="true"></i>
                          中间件
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E9%97%AE%E9%A2%98/">
                          <i class="fa fa-telegram" aria-hidden="true"></i>
                          问题
                        </a>
                      </li>
                    
                      <li>
                        <a href="/categories/%E9%97%B2%E8%B0%88/">
                          <i class="fa fa-vcard" aria-hidden="true"></i>
                          闲谈
                        </a>
                      </li>
                    
                  </ul>
                
              </li>
            
              <li class="navbar-list-item">
                <a href="/tags">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-tags" aria-hidden="true"></i>
                    标签
                  </span>
                </a>
                
                  <ul class="sub-menu">
                    
                      <li>
                        <a href="/tags/%E5%8A%A0%E5%AF%86/">
                          <i class="fa fa-wpexplorer" aria-hidden="true"></i>
                          加密
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/idea/">
                          <i class="fa fa-eercast" aria-hidden="true"></i>
                          idea
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/java/">
                          <i class="fa fa-coffee" aria-hidden="true"></i>
                          java
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/mysql/">
                          <i class="fa fa-database" aria-hidden="true"></i>
                          mysql
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/oracle/">
                          <i class="fa fa-database" aria-hidden="true"></i>
                          oracle
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/spring/">
                          <i class="fa fa-leaf" aria-hidden="true"></i>
                          spring
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/redis/">
                          <i class="fa fa-fire" aria-hidden="true"></i>
                          redis
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/mongodb/">
                          <i class="fa fa-database" aria-hidden="true"></i>
                          mongodb
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/rocketmq/">
                          <i class="fa fa-random" aria-hidden="true"></i>
                          rocketmq
                        </a>
                      </li>
                    
                      <li>
                        <a href="/tags/kafka/">
                          <i class="fa fa-random" aria-hidden="true"></i>
                          kafka
                        </a>
                      </li>
                    
                  </ul>
                
              </li>
            
              <li class="navbar-list-item">
                <a href="/music">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-music" aria-hidden="true"></i>
                    音乐
                  </span>
                </a>
                
              </li>
            
              <li class="navbar-list-item">
                <a href="/links">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-link" aria-hidden="true"></i>
                    友链
                  </span>
                </a>
                
              </li>
            
              <li class="navbar-list-item">
                <a href="/about">
                  <span class="faa-parent animated-hover">
                    <i class="fa  fa-signing" aria-hidden="true"></i>
                    关于
                  </span>
                </a>
                
              </li>
            
      </ul>
    </div>
  </div>
</nav>

  
  <span class="local-search local-search-google local-search-plugin" style="left: calc(50% - 200px);top: 0px;;position:absolute;z-index:2;">
      <input type="search" placeholder="小鹏驿站" id="local-search-input" class="local-search-input-cls" style="">
      <div id="local-search-result" class="local-search-result-cls"></div>
  </span>


  
  

  
  

  
  

  
  

  
  
    <div class="header-content">
      <div class="post-text layout-block">
        <div class="layout-margin">
          <h1 class="title-wrap" title="觉宇宙之无穷，识盈虚之有数">java并发</h1>
          <h2 class="title-sub-wrap">
            <strong>RocPengHua</strong>
            <span>发布于</span>
            <time  class="article-date" datetime="2022-05-28T13:36:09.000Z" itemprop="datePublished">2022-05-28</time>
          </h2>
          <ul class="wrap-list dark">
  
    <li><a href="/categories/java/">📒 java</a></li>
  
</ul>
          <ul class="wrap-list dark">
  
    <li><a href="/tags/%E5%B9%B6%E5%8F%91/">🏷️ 并发</a></li>
  
</ul>
        </div>
      </div>
    </div>
  

  
  
  
</header>

    <!-- 文章 -->

<!-- 文章内容 -->
<div class="body-container">
  <article class="content-container layout-block post-container">
    <div class="widget-info">
      <section class="widget-author widget-item layout-margin content-padding--primary soft-size--large soft-style--box">
  <div class="widget-body">
    
      <img src="/images/p.jpg" class="soft-size--round soft-style--box" alt="RocPengHua">
    
    
      <h2>RocPengHua</h2>
    
    
      <p>天天向上</p>
    

    <div class="count-box">
      <div class="count-box--item">
        <svg class="icon icon-article" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M240.51564747 647.74217627h196.07203239c16.59071043 0 30.16492806-13.57421762 30.16492805-30.16492806V165.10332731c0-33.18142087-30.16492806-60.32985613-60.32985612-60.32985611H245.04038668C225.43318342 104.7734712 210.35071939 119.85593522 210.35071939 139.46313845V617.57724821c0 16.59071043 13.57421762 30.16492806 30.16492808 30.16492806z m663.62841731-452.47392089v482.63884894c0 33.18142087-27.14843525 60.32985613-60.32985612 60.32985613H180.18579134c-33.18142087 0-60.32985613-27.14843525-60.32985612-60.32985613V195.26825538c-49.77213131 0-90.49478418 40.72265287-90.49478417 90.49478417v452.4739209c0 49.77213131 40.72265287 90.49478418 90.49478417 90.49478417h286.56681657c16.59071043 0 30.16492806 13.57421762 30.16492807 30.16492807s13.57421762 30.16492806 30.16492805 30.16492806h90.49478418c16.59071043 0 30.16492806-13.57421762 30.16492805-30.16492806s13.57421762-30.16492806 30.16492807-30.16492807h286.56681657c49.77213131 0 90.49478418-40.72265287 90.49478417-90.49478417V285.76303955c0-49.77213131-40.72265287-90.49478418-90.49478417-90.49478417zM587.41232014 647.74217627h191.54729318c19.60720323 0 34.68966726-15.08246403 34.68966729-34.68966727V134.93839925c0-16.59071043-13.57421762-30.16492806-30.16492808-30.16492805H617.57724821c-30.16492806 0-60.32985613 27.14843525-60.32985612 60.32985611v452.4739209c0 16.59071043 13.57421762 30.16492806 30.16492805 30.16492806z" fill="currentColor"></path>
</svg>
        <span>118</span>
      </div>
      <div class="count-box--item">
        <svg class="icon icon-categories" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M900.3614811 257.09082106h-339.81629553l-67.96326003-101.9448889c-19.41807444-29.12711113-48.54518557-43.69066667-82.52681443-43.69066667H123.6385189c-53.39970333 0-97.09036999 43.69066667-97.09037113 97.09036999v582.54222222c0 53.39970333 43.69066667 97.09036999 97.09037113 97.09037002h776.7229622c53.39970333 0 97.09036999-43.69066667 97.09037113-97.09037002V354.18119104c0-53.39970333-43.69066667-97.09036999-97.09037113-97.09036998z m-97.09036999 242.72592554H220.72888889c-24.27259221 0-48.54518557-24.27259221-48.54518556-48.54518556s24.27259221-48.54518557 48.54518556-48.54518444h582.54222222c24.27259221 0 48.54518557 24.27259221 48.54518556 48.54518444s-24.27259221 48.54518557-48.54518556 48.54518556z" fill="currentColor"></path>
</svg>
        16
      </div>
      <div class="count-box--item">
        <svg class="icon icon-tags" viewBox="0 0 1098 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M283.42180005 272q0-28.38857157-20.09142843-48.48000001t-48.47999998-20.09142842-48.48000002 20.09142842-20.09142846 48.48000001 20.09142846 48.48 48.48000002 20.09142843 48.47999998-20.09142843 20.09142843-48.48zM855.0332285 580.57142843q0 28.38857157-19.81714313 48.2057147l-263.03999997 263.58857157q-20.9142853 19.81714313-48.75428534 19.81714312-28.38857157 0-48.20571468-19.81714312l-383.04-383.58857157q-20.36571468-19.81714313-34.55999999-54.10285688t-14.19428534-62.6742853l0-222.85714313q0-27.84000002 20.36571469-48.20571469t48.2057147-20.36571466l222.85714313 0q28.38857157 0 62.6742853 14.19428529t54.65142842 34.55999999l383.04000001 382.49142843q19.81714313 20.9142853 19.81714314 48.75428532zM1060.74751475 580.57142843q0 28.38857157-19.81714313 48.2057147l-263.04 263.58857157q-20.9142853 19.81714313-48.75428531 19.81714312-19.26857155 0-31.61142843-7.47428531t-28.38857159-24.13714314l251.79428534-251.7942853q19.81714313-19.81714313 19.81714308-48.20571469 0-27.84000002-19.81714308-48.75428531l-383.04000001-382.49142845q-20.36571468-20.36571468-54.65142842-34.55999999t-62.67428532-14.19428534l120 0q28.38857157 0 62.67428532 14.19428534t54.65142842 34.55999999l383.03999998 382.49142845q19.81714313 20.9142853 19.81714314 48.75428531z" fill="currentColor"></path>
</svg>
        40
      </div>
    </div>
  </div>
</section>
      
      
      
      
<section class="widget-toc widget-item layout-margin content-padding--primary soft-size--large soft-style--box">
  <div class="widget-title">
    <svg class="icon icon-toc" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M134.50666666 767.46666668H460.8c27.73333333 0 50.24000001 22.50666668 50.24000001 50.23999999v50.13333333c0 27.73333333-22.50666668 50.24000001-50.24000001 50.24000001H134.50666666c-27.73333333 0-50.24000001-22.50666668-50.23999999-50.24000001v-50.13333333c0.10666668-27.73333333 22.50666668-50.24000001 50.24000001-50.24000001zM84.37333332 541.65333333h326.18666669c27.73333333 0 50.24000001 22.39999999 50.23999999 50.13333334v50.24000001c0 27.73333333-22.50666668 50.24000001-50.24000002 50.23999999H84.37333332c-27.73333333 0-50.24000001-22.50666668-50.23999999-50.23999999v-50.24000001c0-27.73333333 22.50666668-50.13333334 50.24000001-50.13333334zM134.50666666 315.83999999H460.8c27.73333333 0 50.24000001 22.50666668 50.24000001 50.24000001v50.24000001c0 27.73333333-22.50666668 50.13333334-50.24000001 50.13333333H134.50666666c-27.73333333 0-50.24000001-22.39999999-50.23999999-50.13333333v-50.24000001c0.10666668-27.84000001 22.50666668-50.24000001 50.24000001-50.23999999zM209.81333332 89.91999999h326.18666671c27.73333333 0 50.24000001 22.39999999 50.23999997 50.13333335v50.23999999c0 27.73333333-22.50666668 50.24000001-50.24000001 50.24000001H209.81333332c-27.73333333 0-50.24000001-22.50666668-50.23999999-50.24000001v-50.24000001c0-27.73333333 22.50666668-50.13333334 50.24000001-50.13333333zM692.05333333 623.36l274.66666669 176.00000002c23.36000001 14.93333333 30.08 45.97333334 15.14666666 69.33333332L954.77333334 910.93333333c-14.93333333 23.25333334-45.97333334 30.08-69.33333335 15.14666667l-274.66666666-176c-23.36000001-14.93333333-30.08-45.97333334-15.14666667-69.33333333l27.09333334-42.24000001c14.93333333-23.36000001 46.08000001-30.08 69.33333333-15.14666666z" fill="currentColor"></path>
</svg>
    <span>TOC</span>
  </div>
  <div class="widget-body">
    <ol class="toc"><li class="toc-item toc-level-2"><a class="toc-link" href="#synchronized"><span class="toc-number">1.</span> <span class="toc-text">synchronized</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#synchronized%E7%89%B9%E6%80%A7"><span class="toc-number">1.1.</span> <span class="toc-text">synchronized特性</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#synchronized%E7%9A%84%E5%90%8C%E6%AD%A5%E5%AE%9E%E7%8E%B0"><span class="toc-number">1.2.</span> <span class="toc-text">synchronized的同步实现</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%AF%B9%E8%B1%A1%E5%A4%B4"><span class="toc-number">1.3.</span> <span class="toc-text">对象头</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%81%8F%E5%90%91%E9%94%81"><span class="toc-number">1.4.</span> <span class="toc-text">偏向锁</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%BD%BB%E9%87%8F%E7%BA%A7%E9%94%81"><span class="toc-number">1.5.</span> <span class="toc-text">轻量级锁</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E8%87%AA%E6%97%8B%E9%94%81"><span class="toc-number">1.6.</span> <span class="toc-text">自旋锁</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#synchronized%E4%BC%98%E5%8C%96"><span class="toc-number">1.7.</span> <span class="toc-text">synchronized优化</span></a></li><li class="toc-item toc-level-3"><a class="toc-link" href="#synchronized-%E6%96%B9%E5%BC%8F%E7%9A%84%E9%97%AE%E9%A2%98"><span class="toc-number">1.8.</span> <span class="toc-text">synchronized 方式的问题</span></a></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#juc"><span class="toc-number">2.</span> <span class="toc-text">juc</span></a><ol class="toc-child"><li class="toc-item toc-level-3"><a class="toc-link" href="#%E9%94%81%E6%9C%BA%E5%88%B6%E7%B1%BB"><span class="toc-number">2.1.</span> <span class="toc-text">锁机制类</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Lock"><span class="toc-number">2.1.1.</span> <span class="toc-text">Lock</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ReentrantLock"><span class="toc-number">2.1.2.</span> <span class="toc-text">ReentrantLock</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ReentrantReadWriteLock"><span class="toc-number">2.1.3.</span> <span class="toc-text">ReentrantReadWriteLock</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#Condition"><span class="toc-number">2.1.4.</span> <span class="toc-text">Condition</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#LockSupport%E2%80%93%E9%94%81%E5%BD%93%E5%89%8D%E7%BA%BF%E7%A8%8B"><span class="toc-number">2.1.5.</span> <span class="toc-text">LockSupport–锁当前线程</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%8E%9F%E5%AD%90%E6%93%8D%E4%BD%9C%E7%B1%BB"><span class="toc-number">2.2.</span> <span class="toc-text">原子操作类</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#java-util-concurrent-atomic"><span class="toc-number">2.2.1.</span> <span class="toc-text">java.util.concurrent.atomic</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E6%97%A0%E9%94%81%E6%8A%80%E6%9C%AF%E7%9A%84%E5%BA%95%E5%B1%82%E5%AE%9E%E7%8E%B0%E5%8E%9F%E7%90%86"><span class="toc-number">2.2.2.</span> <span class="toc-text">无锁技术的底层实现原理</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#CAS"><span class="toc-number">2.2.3.</span> <span class="toc-text">CAS</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#LongAdder-%E5%AF%B9-AtomicLong-%E7%9A%84%E6%94%B9%E8%BF%9B"><span class="toc-number">2.2.4.</span> <span class="toc-text">LongAdder 对 AtomicLong 的改进</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E7%BA%BF%E7%A8%8B%E6%B1%A0%E7%9B%B8%E5%85%B3%E7%B1%BB"><span class="toc-number">2.3.</span> <span class="toc-text">线程池相关类</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Future"><span class="toc-number">2.3.1.</span> <span class="toc-text">Future</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#FutureTask"><span class="toc-number">2.3.2.</span> <span class="toc-text">FutureTask</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#CompletableFuture"><span class="toc-number">2.3.3.</span> <span class="toc-text">CompletableFuture</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E4%BF%A1%E5%8F%B7%E9%87%8F%E4%B8%89%E7%A7%8D%E5%B7%A5%E5%85%B7%E7%B1%BB"><span class="toc-number">2.4.</span> <span class="toc-text">信号量三种工具类</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#Semaphore-%E4%BF%A1%E5%8F%B7%E9%87%8F"><span class="toc-number">2.4.1.</span> <span class="toc-text">Semaphore - 信号量</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#CountdownLatch"><span class="toc-number">2.4.2.</span> <span class="toc-text">CountdownLatch</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#CyclicBarrier"><span class="toc-number">2.4.3.</span> <span class="toc-text">CyclicBarrier</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#%E5%B0%8F%E7%BB%93"><span class="toc-number">2.4.4.</span> <span class="toc-text">小结</span></a></li></ol></li><li class="toc-item toc-level-3"><a class="toc-link" href="#%E5%B9%B6%E5%8F%91%E9%9B%86%E5%90%88%E7%B1%BB"><span class="toc-number">2.5.</span> <span class="toc-text">并发集合类</span></a><ol class="toc-child"><li class="toc-item toc-level-4"><a class="toc-link" href="#List%E7%BA%BF%E7%A8%8B%E5%AE%89%E5%85%A8"><span class="toc-number">2.5.1.</span> <span class="toc-text">List线程安全</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#CopyOnWriteArrayList"><span class="toc-number">2.5.2.</span> <span class="toc-text">CopyOnWriteArrayList</span></a></li><li class="toc-item toc-level-4"><a class="toc-link" href="#ConcurrentHashMap"><span class="toc-number">2.5.3.</span> <span class="toc-text">ConcurrentHashMap</span></a><ol class="toc-child"><li class="toc-item toc-level-5"><a class="toc-link" href="#Java7-%E5%88%86%E6%AE%B5%E9%94%81"><span class="toc-number">2.5.3.1.</span> <span class="toc-text">Java7 分段锁</span></a></li><li class="toc-item toc-level-5"><a class="toc-link" href="#Java8-%E8%87%AA%E6%97%8B"><span class="toc-number">2.5.3.2.</span> <span class="toc-text">Java8-自旋</span></a></li></ol></li></ol></li></ol></li><li class="toc-item toc-level-2"><a class="toc-link" href="#ThreadLocal"><span class="toc-number">3.</span> <span class="toc-text">ThreadLocal</span></a></li><li class="toc-item toc-level-2"><a class="toc-link" href="#%E5%B9%B6%E8%A1%8CStream"><span class="toc-number">4.</span> <span class="toc-text">并行Stream</span></a></li></ol>
  </div>
</section>

    </div>
  
    <div class="article-info">
      
      
      
      
      <section id="blog-content" class="article-entry markdown-body layout-margin content-padding--large soft-size--large soft-style--box">
        <h2 id="synchronized"><a href="#synchronized" class="headerlink" title="synchronized"></a>synchronized</h2><h3 id="synchronized特性"><a href="#synchronized特性" class="headerlink" title="synchronized特性"></a>synchronized特性</h3><ul>
<li><p>对普通方法加锁，锁是当前实例对象</p>
<pre><code class="prettyprint">public synchronized void test(Object obj)&#123;
   //TODO 
&#125;
</code></pre>
</li>
<li><p>对静态方法加锁，锁是当前类实例，因为类数据存在永久代&#x2F;元空间，因此静态方法锁就是该类的全局锁</p>
<pre><code class="prettyprint">public static synchronized void test(Object obj)&#123;
   //TODO 
&#125;
</code></pre>
</li>
<li><p>对对象加锁，锁是<code>synchronized</code>括号里的对象实例</p>
<pre><code class="prettyprint">synchronized(Object o) &#123;
    //TODO
&#125;
</code></pre>
</li>
</ul>
<h3 id="synchronized的同步实现"><a href="#synchronized的同步实现" class="headerlink" title="synchronized的同步实现"></a>synchronized的同步实现</h3><ul>
<li><p><code>synchronized</code>的锁的实现是基于JVM进入和退出monitor对象来实现的。</p>
</li>
<li><p>monitor对象有2个关键指令monitorenter和monitorexit,具体就是在编译过程中把monitorenter指令插入到同步代码块开始位置，把monitorexit指令插入退出或异常的位置。</p>
</li>
<li><p>线程执行同步代码块的时首先需要获取锁，即尝试获取monitor对象的所有权，具体过程如下</p>
<p>​		首先线程执行指令monitorenter指令尝试获取monitor的所有权，如果monitor的进入数为0，则线程进入进入monitor，并且把进入修改为1，当前线程就持有了锁；如果线程进入monitor时，发现进入数大于0，则会判断monitor的持有者是否为当前线程，如果是当前线程则表示只是重新进入，则对monitor的进入数+1；如果monitor的所有权不是被当前线程持有，线程进入阻塞状态，直到monitor的进入数等于0，再次重新获取monitor的所有权。</p>
</li>
</ul>
<h3 id="对象头"><a href="#对象头" class="headerlink" title="对象头"></a>对象头</h3><p>每个对象分为三块区域:<em>对象头、实例数据和对齐填充</em>。</p>
<ul>
<li>对象头包含两部分，第一部分是Mark Word，用于存储对象自身的运行时数据，如哈希码（HashCode）、GC分代年龄、锁状态标志、线程持有的锁、偏向线程 ID、偏向时间戳等等，这一部分占一个字节。第二部分是Klass Pointer（类型指针），是对象指向它的类元数据的指针，<em>虚拟机通过这个指针来确定这个对象是哪个类的实例</em>，这部分也占一个字节。(<em>如果对象是数组类型的，则需要3个字节来存储对象头，因为还需要一个字节存储数组的长度</em>)</li>
<li>实例数据存放的是类属性数据信息，包括父类的属性信息，如果是数组的实例部分还包括数组的长度，<em>这部分内存按4字节对齐</em>。</li>
<li>填充数据是因为虚拟机要求对象起始地址必须是8字节的整数倍。填充数据不是必须存在的，仅仅是为了字节对齐。</li>
</ul>
<p>对象头信息是与对象自身定义的数据无关的额外存储成本，考虑到虚拟机的空间效率，Mark Word被设计成一个非固定的数据结构以便在极小的空间内存储尽量多的信息，它会根据对象的状态复用自己的存储空间。例如在32位的HotSpot虚拟机 中对象未被锁定的状态下，Mark Word的32个Bits空间中的25Bits用于存储对象哈希码(HashCode)，4Bits用于存储对象分代年龄，2Bits用于存储锁标志 位，1Bit固定为0，在其他状态(轻量级锁定、重量级锁定、GC标记、可偏向)下对象的存储内容如下表所示</p>
<img src="/2022/05/28/java-bing-fa/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L2ppbmppbmlhbzE=,size_16,color_FFFFFF,t_70.png" class="asset-class" title="对象头存储结构">

<p>从对象头的存储内容可以看出<strong>锁的状态都保存在对象头</strong>中，Synchronized也不例外，当其从轻量级锁膨胀为重量级锁时，锁标识位为10，其中<em>指针指向的是monitor对象</em>(也称为管程或监视器锁)的起始地址。</p>
<h3 id="偏向锁"><a href="#偏向锁" class="headerlink" title="偏向锁"></a>偏向锁</h3><p>偏向锁的核心思想是，如果一个线程获得了锁，那么锁就进入偏向模式，此时Mark Word 的结构也变为偏向锁结构，当这个线程再次请求锁时，无需再做任何同步操作，即获取锁的过程，这样就省去了大量有关锁申请的操作，从而也就提升程序的性能。所以，对于没有锁竞争的场合，偏向锁有很好的优化效果，毕竟极有可能连续多次是同一个线程申请相同的锁。<br>但是对于锁竞争比较激烈的场合，偏向锁就失效了，因为这样场合极有可能每次申请锁的线程都是不相同的，因此这种场合下不应该使用偏向锁，否则会得不偿失，需要注意的是，偏向锁失败后，并不会立即膨胀为重量级锁，而是先升级为轻量级锁。</p>
<ul>
<li>获取锁</li>
</ul>
<ol>
<li>检测Mark Word是否为可偏向状态，即是否为偏向锁1，锁标识位为01；</li>
<li>若为可偏向状态，则测试线程ID是否为当前线程ID，如果是，则执行步骤(5)，否则执行步骤(3)；</li>
<li>如果线程ID不为当前线程ID，则<strong>通过CAS操作竞争锁</strong>，竞争成功，则将Mark Word的线程ID替换为当前线程ID，否则执行线程(4)；</li>
<li>通过CAS竞争锁失败，证明当前存在多线程竞争情况，当到达全局安全点，获得偏向锁的线程被挂起，偏向锁升级为轻量级锁，然后被阻塞在安全点的线程继续往下执行同步代码块；</li>
<li>执行同步代码块</li>
</ol>
<ul>
<li>释放锁</li>
</ul>
<p>偏向锁的释放采用了一种只有竞争才会释放锁的机制，线程是不会主动去释放偏向锁，需要等待其他线程来竞争。偏向锁的撤销需要等待全局安全点（这个时间点是上没有正在执行的代码）</p>
<ol>
<li>暂停拥有偏向锁的线程，判断锁对象是否还处于被锁定状态；</li>
<li>撤销偏向锁，恢复到无锁状态(01)或者轻量级锁的状态；</li>
</ol>
<h3 id="轻量级锁"><a href="#轻量级锁" class="headerlink" title="轻量级锁"></a>轻量级锁</h3><p>引入轻量级锁的主要原因是，对绝大部分的锁，在整个同步周期内都不存在竞争，可能是交替获取锁然后执行。(<strong>与偏向锁的区别是，引入偏向锁是假设同一个锁都是由同一线程多次获得，而轻量级锁是假设同一个锁是由n个线程交替获得；相同点是都是假设不存在多线程竞争</strong>)<br>引入轻量级锁的主要目的是，在没有多线程竞争的前提下，减少传统的重量级锁使用操作系统互斥量产生的性能消耗(多指时间消耗)。<br>触发轻量级锁的条件是当关闭偏向锁功能或者多个线程竞争偏向锁导致偏向锁升级为轻量级锁，则会尝试获取轻量级锁，此时Mark Word的结构也变为轻量级锁的结构。<strong>如果存在多个线程同一时间访问同一锁的场合，就会导致轻量级锁膨胀为重量级锁</strong>。</p>
<ul>
<li>获取锁<ol>
<li>判断当前对象是否处于无锁状态（hashcode、0、01），若是，则JVM首先将在当前线程的<em>栈帧</em>中建立一个名为锁记录（Lock Record）的空间，用于存储锁对象目前的Mark Word的拷贝（官方把这份拷贝加了一个Displaced前缀，即Displaced Mark Word）；否则执行步骤（3）；</li>
<li>JVM利用CAS操作尝试将对象的Mark Word更新为指向Lock Record的指针，如果成功表示竞争到锁，则将锁标志位变成00（表示此对象处于轻量级锁状态），执行同步操作；如果失败则执行步骤（3）；</li>
<li>判断当前对象的Mark Word是否指向当前线程的栈帧，如果是则表示当前线程已经持有当前对象的锁，则直接执行同步代码块；否则只能说明该锁对象已经被其他线程抢占了，这时轻量级锁需要膨胀为重量级锁，锁标志位变成10，后面等待的线程将会进入阻塞状态；</li>
</ol>
</li>
<li>释放锁<ol>
<li>取出在获取轻量级锁保存在Displaced Mark Word中的数据；</li>
<li>用CAS操作将取出的数据替换当前对象的Mark Word中，如果成功，则说明释放锁成功，否则执行（3）；</li>
<li>如果CAS操作替换失败，说明有其他线程尝试获取该锁，则需要在释放锁的同时需要唤醒被挂起的线程。</li>
</ol>
</li>
</ul>
<h3 id="自旋锁"><a href="#自旋锁" class="headerlink" title="自旋锁"></a>自旋锁</h3><p>线程的阻塞和唤醒需要CPU从用户态转为核心态，频繁的阻塞和唤醒对CPU来说是一件负担很重的工作，势必会给系统的并发性能带来很大的压力。同时我们发现在许多应用上面，对象锁的锁状态只会持续很短一段时间，为了这一段很短的时间频繁地阻塞和唤醒线程是非常不值得的。所以引入自旋锁。</p>
<p>轻量级锁失败后，虚拟机为了避免线程真实地在操作系统层面挂起，还会进行一项称为自旋锁的优化手段。如果自旋之后依然没有获取到锁，也就只能升级为重量级锁了。</p>
<ol>
<li>当一个线程(假设叫A线程)想要获得锁时，首先检查对象头中的锁标志，如果是偏向锁，则跳转到2,如果是无锁状态，则跳转到3</li>
<li>检查对象头中的偏向线程id是否指向A线程，是,则直接执行同步代码块,不是则3。</li>
<li>使用cas操作将替换对象头中的偏向线程id,成功，则直接执行同步代码块。失败则说明其他的线程(假设叫B线程)已经拥有偏向锁了,那么进行偏向锁的撤销(因为这里有竞争了)，此时执行4。</li>
<li>B线程运行到全局安全点后，暂停该线程，检查它的状态,如果处于不活动或者已经退出同步代码块则原持有偏向锁的线程释放锁，然后A再次执行3。如果仍处于活动状态，则需要升级为轻量级锁，此时执行5。</li>
<li>在B线程的栈中分配锁记录，拷贝对象头中的MarkWord到锁记录中，然后将MarkWord改为指向B线程，同时将对象头中的锁标志信息改为轻量级锁的00,然后唤醒B线程，也就是从安全点处继续执行。</li>
<li>由于锁升级为轻量级锁, A线程也进行相同的操作，即，在A线程的栈中分配锁记录，拷贝对象头中的Mark Word到锁记录中，然后使用cas操作替换MarkWord,因为此时B线程拥有锁，因此, A线程自旋。如果自旋一定次数内成功获得锁，那么A线程获得轻量级锁，执行同步代码块。若自旋后仍未获得锁，A升级为重量级锁，将对象头中的锁标志信息改为重量级的10，同时阻塞,此时请看7。</li>
<li>B线程在释放锁的时候，使用cas将MarkWord中的信息替换，成功，则表示无竞争(这个时候还是轻量级锁, A线程可能正在自旋中)直接释放。失败(因为这个时候锁已经膨胀)，那么释放之 后唤醒被挂起的线程(在这个例子中，也就是A)。</li>
</ol>
<h3 id="synchronized优化"><a href="#synchronized优化" class="headerlink" title="synchronized优化"></a>synchronized优化</h3><ul>
<li><p>自旋与自适应自旋</p>
<p>如果持有锁的线程能在很短时间内释放锁资源，就可以让线程执行一个忙循环（自旋），等持有锁的线程释放锁后即可立即获取锁，这样就避免用户线程和内核的切换的消耗。但是线程自旋需要消耗cpu的资源，如果一直得不到锁就会浪费cpu资源。因此在jdk1.6引入了自适应自旋锁，自旋等待的时候不固定，而是由前一次在同一个锁上的自旋时间及锁的拥有者的状态来决定。</p>
</li>
<li><p>锁消除</p>
<p>锁消除是指虚拟机即时编译器在运行时，对于一些代码上要求同步但是被检测不可能存在共享数据竞争的锁进行消除。例如String类型的连接操作，String是一个不可变对象，字符串的连接操作总是通过生成新的String对象来进行的，Javac编译器会对String连接做自动优化，在JDK1.5的版本中使用的是StringBuffer对象的append操作，StringBuffer的append方法是同步方法，这段代码在经过即时编译器编译之后就会忽略掉所有的同步直接执行。在JDK1.5之后是使用的StringBuilder对象的append操作来优化字符串连接的。</p>
</li>
<li><p>锁粗化</p>
<p>将多次连接在一起的加锁、解锁操作合并为一次，将多个连续的锁扩展成一个范围更大的锁。例如每次调用StringBuffer.append方法都需要加锁，如果虚拟机检测到有一系列的连续操作都是对同一个对象反复加锁和解锁，就会将其合并成一个更大范围的加锁和解锁操作。</p>
</li>
</ul>
<h3 id="synchronized-方式的问题"><a href="#synchronized-方式的问题" class="headerlink" title="synchronized 方式的问题"></a>synchronized 方式的问题</h3><ul>
<li>同步块的阻塞无法中断（不能 Interruptibly）</li>
<li>同步块的阻塞无法控制超时（无法自动解锁）</li>
<li>同步块无法异步处理锁（即不能立即知道是否可以拿到锁）</li>
<li>同步块无法根据条件灵活的加锁解锁（即只能跟同步块范围一致）</li>
</ul>
<h2 id="juc"><a href="#juc" class="headerlink" title="juc"></a>juc</h2><h3 id="锁机制类"><a href="#锁机制类" class="headerlink" title="锁机制类"></a>锁机制类</h3><h4 id="Lock"><a href="#Lock" class="headerlink" title="Lock"></a>Lock</h4><ul>
<li><p>使用方式灵活可控</p>
</li>
<li><p>性能开销较小</p>
</li>
<li><p>接口设计</p>
<ul>
<li><p><code>void lock();</code>获取锁</p>
</li>
<li><p><code>void lockInterruptibly() throws InterruptedException;</code>获取锁; 允许打断;</p>
</li>
<li><p><code>boolean tryLock(long time, TimeUnit unit) throws InterruptedException;</code>尝试获取锁; 成功则返回 true; 超时则退出</p>
</li>
<li><p><code>boolean tryLock();</code>尝试【无等待】获取锁; 成功则返回 true</p>
</li>
<li><p><code>void unlock</code>解锁；要求当前线程已获得锁; 类比同步块结束</p>
</li>
<li><p><code>Condition newCondition();</code>新增一个绑定到当前Lock的条件； </p>
<pre><code class="prettyprint">//示例: （类比: Object monitor） 
final Lock lock = new ReentrantLock(); 
final Condition notFull = lock.newCondition(); 
final Condition notEmpty = lock.newCondition();
</code></pre>
</li>
</ul>
</li>
</ul>
<h4 id="ReentrantLock"><a href="#ReentrantLock" class="headerlink" title="ReentrantLock"></a>ReentrantLock</h4><ul>
<li><p>代码示例</p>
<ul>
<li><p><code>Count</code>类定义<code>ReentrantLock</code>的读写方法</p>
<pre><code class="prettyprint">public class Count &#123;

    final ReentrantLock lock = new ReentrantLock();

    public void get() &#123;
        try &#123;
            lock.lock();
            System.out.println(Thread.currentThread().getName() + &quot; get begin&quot;);
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + &quot; get end&quot;);
            lock.unlock();
        &#125; catch (InterruptedException e) &#123;
            e.printStackTrace();
        &#125;
    &#125;

    public void put() &#123;
        try &#123;
            lock.lock();
            System.out.println(Thread.currentThread().getName() + &quot; put begin&quot;);
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + &quot; put end&quot;);
            lock.unlock();
        &#125; catch (InterruptedException e) &#123;
            e.printStackTrace();
        &#125;
    &#125;
&#125;
</code></pre>
</li>
<li><p><code>ReentrantLockDemo</code>测试类</p>
<pre><code class="prettyprint">public class ReentrantLockDemo &#123;

    public static void main(String[] args) &#123;
        final Count count = new Count();

        for (int i = 0; i &lt; 2; i++) &#123;
            new Thread(count::get).start();
        &#125;

        for (int i = 0; i &lt; 2; i++) &#123;
            new Thread(count::put).start();
        &#125;
    &#125;
&#125;
</code></pre>
</li>
</ul>
</li>
<li><p>测试结果</p>
<img src="/2022/05/28/java-bing-fa/image-20220528215049400.png" class="asset-class" title="image-20220528215049400"></li>
</ul>
<h4 id="ReentrantReadWriteLock"><a href="#ReentrantReadWriteLock" class="headerlink" title="ReentrantReadWriteLock"></a>ReentrantReadWriteLock</h4><ul>
<li><p>ReadWriteLock 管理一组锁，一个读锁，一个写锁。</p>
</li>
<li><p>读锁可以在没有写锁的时候被多个线程同时持有，写锁是独占的。</p>
</li>
<li><p>所有读写锁的实现必须确保写操作对读操作的内存影响。每次只能有一个写线程，但是 同时可以有多个线程并发地读数据。ReadWriteLock 适用于读多写少的并发情况。</p>
</li>
<li><p>代码示例</p>
<ul>
<li><p><code>Count2</code>类定义<code>ReentrantReadWriteLock</code>的读写方法</p>
<pre><code class="prettyprint">public class Count2 &#123;

    private final ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

    public void get() &#123;
        rwLock.readLock().lock();
        try &#123;
            System.out.println(Thread.currentThread().getName() + &quot; get begin&quot;);
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + &quot; get end&quot;);
        &#125; catch (InterruptedException e) &#123;
            e.printStackTrace();
        &#125; finally &#123;
            rwLock.readLock().unlock();
        &#125;
    &#125;

    public void put() &#123;
        rwLock.writeLock().lock();
        try &#123;
            System.out.println(Thread.currentThread().getName() + &quot; put begin&quot;);
            Thread.sleep(1000);
            System.out.println(Thread.currentThread().getName() + &quot; put end&quot;);
        &#125; catch (InterruptedException e) &#123;
            e.printStackTrace();
        &#125; finally &#123;
            rwLock.writeLock().unlock();
        &#125;
    &#125;
&#125;
</code></pre>
</li>
<li><p><code>ReentrantReadWriteLockDemo</code> 测试类</p>
<pre><code class="prettyprint">public class ReentrantReadWriteLockDemo &#123;

    public static void main(String[] args) &#123;
        final Count2 count = new Count2();

        for (int i = 0; i &lt; 5; i++) &#123;
            new Thread(() -&gt; count.get()).start();
        &#125;

        for (int i = 0; i &lt; 5; i++) &#123;
            new Thread(() -&gt; count.put()).start();
        &#125;
    &#125;
    // 读锁不互斥、写锁互斥
&#125;
</code></pre>
</li>
<li><p>运行结果</p>
<img src="/2022/05/28/java-bing-fa/image-20220528223705002.png" class="asset-class" title="image-20220528223705002"></li>
</ul>
</li>
</ul>
<h4 id="Condition"><a href="#Condition" class="headerlink" title="Condition"></a>Condition</h4><p>通过 lock.newCondition()创建。 可以看做是 Lock 对象上的信号。类似于 wait&#x2F;notify。</p>
<ul>
<li><code>void await() throws  InterruptedException;</code> 等待信号; 类比 Object#wait() </li>
<li><code>void awaitUninterruptibly();</code> 等待信号;  </li>
<li><code>boolean await(long time, TimeUnit unit) throws InterruptedException;</code> 等待信号; 超时则返回 false </li>
<li><code>boolean awaitUntil(Date deadline) throws InterruptedException;</code> 等待信号; 超时则返回 false </li>
<li><code>void signal();</code>给一个等待线程发送唤醒信号; 类比 Object#notify () </li>
<li><code>void signalAll();</code> 给所有等待线程发送唤醒信号; 类比 Object#notifyAll()</li>
</ul>
<p>测试</p>
<pre><code class="prettyprint">class ConditionDemo &#123;
    final Lock lock = new ReentrantLock();
    final Condition notFull  = lock.newCondition();
    final Condition notEmpty = lock.newCondition();
    
    final Object[] items = new Object[10];
    int putptr, takeptr, count;
    
    public void put(Object x) throws InterruptedException &#123;
        lock.lock();
        try &#123;
            // 当count等于数组的大小时，当前线程等待，直到notFull通知，再进行生产
            while (count == items.length)
                notFull.await();
            items[putptr] = x;
            if (++putptr == items.length) putptr = 0;
            ++count;
            notEmpty.signal();
        &#125; finally &#123;
            lock.unlock();
        &#125;
    &#125;
    
    public Object take() throws InterruptedException &#123;
        lock.lock();
        try &#123;
            // 当count为0，进入等待，直到notEmpty通知，进行消费。
            while (count == 0)
                notEmpty.await();
            Object x = items[takeptr];
            if (++takeptr == items.length) takeptr = 0;
            --count;
            notFull.signal();
            return x;
        &#125; finally &#123;
            lock.unlock();
        &#125;
    &#125;
&#125;
</code></pre>
<h4 id="LockSupport–锁当前线程"><a href="#LockSupport–锁当前线程" class="headerlink" title="LockSupport–锁当前线程"></a>LockSupport–锁当前线程</h4><p>LockSupport 类似于 Thread 类的静态方法，专门处理（执行这个代码的）本线程的</p>
<p>为什么 unpark 需要加一个线程作为参数？ 因为一个 park 的线程，无法自己唤醒自己，所以需要其他线程来唤醒。</p>
<ul>
<li><code>public static void park(Object blocker)</code> 暂停当前线程</li>
<li><code>public static void parkNanos(Object blocker, long nanos)</code> 暂停当前线程，有超时时间的限制</li>
<li><code>public static void parkUntil(Object blocker, long deadline)</code> 暂定当前线程，直到某个时间</li>
<li><code>public static void park()</code> 无期限暂停当前线程</li>
<li><code>public static void parkNanos(long nanos)</code> 暂停当前线程，有超时时间限制</li>
<li><code>public static void parkUntil(long deadline)</code> 暂定当前线程，直到某个时间</li>
<li><code>public static void unpark(Thread thread)</code>恢复当前线程</li>
<li><code>public static Object getBlocker(Thread t)</code></li>
</ul>
<p>测试</p>
<pre><code class="prettyprint">public class LockSupportDemo &#123;
    
    public static Object u = new Object();
    static ChangeObjectThread t1 = new ChangeObjectThread(&quot;t1&quot;);
    static ChangeObjectThread t2 = new ChangeObjectThread(&quot;t2&quot;);
    
    public static class ChangeObjectThread extends Thread &#123;
        public ChangeObjectThread(String name) &#123;
            super(name);
        &#125;
        @Override public void run() &#123;
            synchronized (u) &#123;
                System.out.println(&quot;in &quot; + getName());
                LockSupport.park();
                if (Thread.currentThread().isInterrupted()) &#123;
                    System.out.println(Thread.currentThread().getName() + &quot;被中断了&quot;);
                &#125;
                System.out.println(Thread.currentThread().getName() + &quot;继续执行&quot;);
            &#125;
        &#125;
    &#125;
    
    public static void main(String[] args) throws InterruptedException &#123;
        t1.start();
        Thread.sleep(1000L);
        t2.start();
        Thread.sleep(3000L);
        t1.interrupt();
        LockSupport.unpark(t2);
        t1.join();
        t2.join();
    &#125;
&#125;
</code></pre>
<img src="/2022/05/28/java-bing-fa/image-20220528224817320.png" class="asset-class" title="image-20220528224817320">

<h3 id="原子操作类"><a href="#原子操作类" class="headerlink" title="原子操作类"></a>原子操作类</h3><h4 id="java-util-concurrent-atomic"><a href="#java-util-concurrent-atomic" class="headerlink" title="java.util.concurrent.atomic"></a>java.util.concurrent.atomic</h4><img src="/2022/05/28/java-bing-fa/image-20220528225129911.png" class="asset-class" title="image-20220528225129911">

<h4 id="无锁技术的底层实现原理"><a href="#无锁技术的底层实现原理" class="headerlink" title="无锁技术的底层实现原理"></a>无锁技术的底层实现原理</h4><ul>
<li><p>Unsafe API - Compare-And-Swap</p>
</li>
<li><p>CPU 硬件指令支持: CAS 指令</p>
</li>
<li><p>核心实现原理：</p>
<ul>
<li><p>volatile 保证读写操作都可见（注意不保证原子）； </p>
<img src="/2022/05/28/java-bing-fa/image-20220528225929218.png" class="asset-class" title="image-20220528225929218">
</li>
<li><p>使用 CAS 指令，作为乐观锁实现，通过自旋重试保证写入</p>
<img src="/2022/05/28/java-bing-fa/image-20220528230009442.png" class="asset-class" title="image-20220528230009442">

<img src="/2022/05/28/java-bing-fa/image-20220528230022453.png" class="asset-class" title="image-20220528230022453">

<img src="/2022/05/28/java-bing-fa/image-20220528230039040.png" class="asset-class" title="image-20220528230039040"></li>
</ul>
</li>
</ul>
<h4 id="CAS"><a href="#CAS" class="headerlink" title="CAS"></a>CAS</h4><p>CAS 本质上没有使用锁。 并发压力跟锁性能的关系： </p>
<ul>
<li>压力非常小，性能本身要求就不高； </li>
<li>压力一般的情况下，无锁更快，大部分都一次写入；</li>
<li>压力非常大时，自旋导致重试过多，资源消耗很大。</li>
</ul>
<p>代码示例</p>
<ul>
<li><p><code>Count</code>增加获取工具类，无锁，非同步</p>
<pre><code class="prettyprint">public class Count &#123;

    private int num = 0;

    public int add() &#123;
        return num++;
    &#125;

    public int getNum() &#123;
        return num;
    &#125;
&#125;
</code></pre>
</li>
<li><p><code>SyncCount</code>增加和获取工具类，同步</p>
</li>
<li><p><code>AtomicCount</code>增加和获取工具类，原子类</p>
<pre><code class="prettyprint">public class AtomicCount &#123;

    private AtomicInteger num = new AtomicInteger();

    public int add() &#123;
        return num.getAndIncrement();
    &#125;

    public int getNum() &#123;
        return num.get();
    &#125;
&#125;
</code></pre>
</li>
<li><p>测试类</p>
<pre><code class="prettyprint">public class AtomicMain &#123;

    public static void main(String[] args) &#123;
//        final Count count = new Count(); // &lt;1000000
//        final SyncCount count = new SyncCount(); // 1000000
        final AtomicCount count = new AtomicCount(); // 1000000
        for (int i = 0; i &lt; 100; i++) &#123;
            new Thread(() -&gt; &#123;
                for (int j = 0; j &lt; 10000; j++) &#123;
                    count.add();
                &#125;
            &#125;).start();
        &#125;

        try &#123;
            Thread.sleep(5000L);
        &#125; catch (InterruptedException e) &#123;
            e.printStackTrace();
        &#125;

        System.out.println(&quot;num=&quot; + count.getNum());
    &#125;

&#125;
</code></pre>
<h4 id="LongAdder-对-AtomicLong-的改进"><a href="#LongAdder-对-AtomicLong-的改进" class="headerlink" title="LongAdder 对 AtomicLong 的改进"></a>LongAdder 对 AtomicLong 的改进</h4><pre><code class="prettyprint">LongAdder 的改进思路：
1、AtomicInteger 和 AtomicLong 里的 value 是所有
线程竞争读写的热点数据；
2、将单个 value 拆分成跟线程一样多的数组 Cell[]；
3、每个线程写自己的 Cell[i]++，最后对数组求和。
</code></pre>
</li>
</ul>
<h3 id="线程池相关类"><a href="#线程池相关类" class="headerlink" title="线程池相关类"></a>线程池相关类</h3><h4 id="Future"><a href="#Future" class="headerlink" title="Future"></a>Future</h4><ul>
<li>单个线程&#x2F;任务的执行结果</li>
</ul>
<pre><code class="prettyprint">public class FutureDemo &#123;
    public static void main(String[] args) &#123;
        ExecutorService executor = Executors.newCachedThreadPool();
        Future&lt;Integer&gt; result = executor.submit(new Callable&lt;Integer&gt;() &#123;
            public Integer call() throws Exception &#123;
                return new Random().nextInt();
            &#125;
        &#125;);
        executor.shutdown();
        try &#123;
            System.out.println(&quot;result:&quot; + result.get());
        &#125; catch (InterruptedException e) &#123;
            e.printStackTrace();
        &#125; catch (ExecutionException e) &#123;
            e.printStackTrace();
        &#125;
    &#125;
&#125;
</code></pre>
<h4 id="FutureTask"><a href="#FutureTask" class="headerlink" title="FutureTask"></a>FutureTask</h4><ul>
<li>单个线程&#x2F;任务的执行结果</li>
</ul>
<pre><code class="prettyprint">public class FutureTask &#123;
    public static void main(String[] args) &#123;
        //第一种方式
        FutureTask&lt;Integer&gt; task = new FutureTask&lt;Integer&gt;(new Callable&lt;Integer&gt;() &#123;
            @Override
            public Integer call() throws Exception &#123;
                return new Random().nextInt();
            &#125;
        &#125;);
        new Thread(task).start();
        //第二种方方式
//        ExecutorService executor = Executors.newSingleThreadExecutor();
//        FutureTask&lt;Integer&gt; task = new FutureTask&lt;Integer&gt;(new Callable&lt;Integer&gt;() &#123;
//            @Override
//            public Integer call() throws Exception &#123;
//                return new Random().nextInt();
//            &#125;
//        &#125;);
//        executor.submit(task);
        
        try &#123;
            System.out.println(&quot;result: &quot; + task.get());
        &#125; catch (InterruptedException e) &#123;
            e.printStackTrace();
        &#125; catch (ExecutionException e) &#123;
            e.printStackTrace();
        &#125;
    &#125;
    
&#125;
</code></pre>
<h4 id="CompletableFuture"><a href="#CompletableFuture" class="headerlink" title="CompletableFuture"></a>CompletableFuture</h4><ul>
<li>异步，回调，组合, 功能强大</li>
</ul>
<pre><code class="prettyprint">public class CompletableFutureDemo &#123;
    
    public static void main(String[] args)&#123;
        // 1.变换结果
        System.out.println(&quot;=====&gt;1.变换结果&quot;);
        String result1 = CompletableFuture.supplyAsync(()-&gt;&#123;
            return &quot;Hello &quot;;
        &#125;).thenApplyAsync(v -&gt; v + &quot;world&quot;)
                .join();
        System.out.println(result1);
        // 2.消费
        CompletableFuture.supplyAsync(()-&gt;&#123;return &quot;Hello &quot;;&#125;)
                .thenAccept(v -&gt; &#123;
                    System.out.println(&quot;=====&gt;2.消费&quot;);
                    System.out.println(&quot;consumer: &quot; + v);
                &#125;);
        
        // 3.组合
        System.out.println(&quot;=====&gt;3.组合&quot;);
        String result3 = CompletableFuture.supplyAsync(()-&gt;&#123;
            try &#123;
                Thread.sleep(1000);
            &#125; catch (InterruptedException e) &#123;
                e.printStackTrace();
            &#125;
            return &quot;Hello&quot;;
        &#125;).thenCombine(CompletableFuture.supplyAsync(()-&gt;&#123;         
            try &#123;
                Thread.sleep(2000);
            &#125; catch (InterruptedException e) &#123;
                e.printStackTrace();
            &#125;
            return &quot;world&quot;;
        &#125;),(s1,s2)-&gt;&#123;return s1 + &quot; &quot; + s2;&#125;).join();
        System.out.println(&quot;thenCombine:&quot;+result3);
    
        CompletableFuture.supplyAsync(() -&gt; &quot;Hello, java course.&quot;)
                .thenApply(String::toUpperCase).thenCompose(s -&gt; CompletableFuture.supplyAsync(s::toLowerCase))
                .thenAccept(v -&gt; &#123; System.out.println(&quot;thenCompose:&quot;+v);&#125;);
        // 4.竞争
        System.out.println(&quot;=====&gt;4.竞争&quot;);
        String result4 = CompletableFuture.supplyAsync(()-&gt;&#123;
            try &#123;
                Thread.sleep(100);
            &#125; catch (InterruptedException e) &#123;
                e.printStackTrace();
            &#125;
            return &quot;Hi Boy&quot;;
        &#125;).applyToEither(CompletableFuture.supplyAsync(()-&gt;&#123;
            try &#123;
                Thread.sleep(300);
            &#125; catch (InterruptedException e) &#123;
                e.printStackTrace();
            &#125;
            return &quot;Hi Girl&quot;;
        &#125;),(s)-&gt;&#123;return s;&#125;).join();
        System.out.println(result4);
        // 5.补偿异常
        System.out.println(&quot;=====&gt;5.补偿异常&quot;);
        String result5 = CompletableFuture.supplyAsync(()-&gt;&#123;
            try &#123;
                Thread.sleep(100);
            &#125; catch (InterruptedException e) &#123;
                e.printStackTrace();
            &#125;
            if(true) &#123;
                throw new RuntimeException(&quot;exception test!&quot;);
            &#125;
            return &quot;Hi Boy&quot;;
        &#125;).exceptionally(e-&gt;&#123;                // Fluent API      
            System.out.println(e.getMessage());
            return &quot;Hello world!&quot;;
        &#125;).join();
        System.out.println(result5); 
    &#125;   
&#125;
</code></pre>
<img src="/2022/05/28/java-bing-fa/image-20220528234046204.png" class="asset-class" title="image-20220528234046204">

<h3 id="信号量三种工具类"><a href="#信号量三种工具类" class="headerlink" title="信号量三种工具类"></a>信号量三种工具类</h3><h4 id="Semaphore-信号量"><a href="#Semaphore-信号量" class="headerlink" title="Semaphore - 信号量"></a>Semaphore - 信号量</h4><ul>
<li>准入数量为N</li>
<li>N&#x3D;1时则等价于独占锁</li>
<li>使用场景，同一时间控制并发线程数</li>
</ul>
<pre><code class="prettyprint">public Semaphore(int permits) &#123;          //参数permits表示许可数目，即同时可以允许多少线程进行访问
    sync = new NonfairSync(permits);
&#125;
public Semaphore(int permits, boolean fair) &#123;    //这个多了一个参数fair表示是否是公平的，即等待时间越久的越先获取许可
    sync = (fair)? new FairSync(permits) : new NonfairSync(permits);
&#125;
public void acquire() throws InterruptedException &#123;  &#125;     //获取一个许可
public void acquire(int permits) throws InterruptedException &#123; &#125;    //获取permits个许可
public void release() &#123; &#125;          //释放一个许可
public void release(int permits) &#123; &#125;    //释放permits个许可
</code></pre>
<p>代码示例<code>SemaphoreDemo</code></p>
<pre><code class="prettyprint">public class SemaphoreDemo &#123;
    
    public static void main(String[] args) &#123;
        int N = 8;            //工人数
        Semaphore semaphore = new Semaphore(2); //机器数目
        for (int i = 0; i &lt; N; i++)
            new Worker(i, semaphore).start();
    &#125;
    static class Worker extends Thread &#123;
        private int num;
        private Semaphore semaphore;
        public Worker(int num, Semaphore semaphore) &#123;
            this.num = num;
            this.semaphore = semaphore;
        &#125;
        @Override
        public void run() &#123;
            try &#123;
                semaphore.acquire();  // 在子线程里控制资源占用
                System.out.println(&quot;工人&quot; + this.num + &quot;占用一个机器在生产...&quot;);
                Thread.sleep(2000);
                System.out.println(&quot;工人&quot; + this.num + &quot;释放出机器&quot;);
                semaphore.release();   // 在子线程里控制释放资源占用
            &#125; catch (InterruptedException e) &#123;
                e.printStackTrace();
            &#125;
        &#125;
    &#125;
&#125;
</code></pre>
<img src="/2022/05/28/java-bing-fa/image-20220528231859010.png" class="asset-class" title="image-20220528231859010">

<p>代码示例<code>SemaphoreDemo2</code>获取多个许可</p>
<pre><code class="prettyprint">public class SemaphoreDemo2 &#123;
    private final static int threadCount = 20;
    public static void main(String[] args) throws Exception &#123;
        ExecutorService exec = Executors.newCachedThreadPool();
        final Semaphore semaphore = new Semaphore(7);
        for (int i = 0; i &lt; threadCount; i++) &#123;
            final int threadNum = i;
            exec.execute(() -&gt; &#123;
                try &#123;
                    semaphore.acquire(3); // 获取全部许可，退化成串行执行
                    test(threadNum);
                    semaphore.release(3); // 释放多个许可
                &#125; catch (Exception e) &#123;
                    e.printStackTrace();
                &#125;
            &#125;);
        &#125;
        exec.shutdown();
    &#125;
    private static void test(int threadNum) throws Exception &#123;
        System.out.println(&quot;id:&quot; + threadNum + &quot;,&quot; + Thread.currentThread().getName());
        Thread.sleep(1000);
    &#125;
&#125;
</code></pre>
<img src="/2022/05/28/java-bing-fa/image-20220528232146316.png" class="asset-class" title="image-20220528232146316">

<h4 id="CountdownLatch"><a href="#CountdownLatch" class="headerlink" title="CountdownLatch"></a>CountdownLatch</h4><p>Master 线程等待 Worker 线程把任务执行完（做减号，只能使用一次,在主线程await()）</p>
<pre><code class="prettyprint">public CountDownLatch(int count) &#123;  &#125;;  //参数count为计数值
public void await() throws InterruptedException &#123; &#125;;//调用await()方法的线程会被挂起，它会等待直到count值为0才继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException &#123; &#125;;  //和await()类似，只不过等待一定的时间后count值还没变为0的话就会继续执行
public void countDown() &#123; &#125;;  //将count值减1
</code></pre>
<p>代码示例<code>CountDownLatchDemo</code></p>
<pre><code class="prettyprint">public class CountDownLatchDemo &#123;
    public static void main(String[] args) throws InterruptedException &#123;
        CountDownLatch countDownLatch = new CountDownLatch(5);
        for(int i=0;i&lt;5;i++)&#123;
            new Thread(new readNum(i,countDownLatch)).start();
        &#125;
        countDownLatch.await(); // 注意跟CyclicBarrier不同，这里在主线程await
        System.out.println(&quot;==&gt;各个子线程执行结束。。。。&quot;);
        System.out.println(&quot;==&gt;主线程执行结束。。。。&quot;);
    &#125;
    static class readNum  implements Runnable&#123;
        private int id;
        private CountDownLatch latch;
        public readNum(int id,CountDownLatch latch)&#123;
            this.id = id;
            this.latch = latch;
        &#125;
        @Override
        public void run() &#123;
            synchronized (this)&#123;
                System.out.println(&quot;id:&quot;+id+&quot;,&quot;+Thread.currentThread().getName());
                //latch.countDown();
                System.out.println(&quot;线程组任务&quot;+id+&quot;结束，其他任务继续&quot;);
                latch.countDown();
            &#125;
        &#125;
    &#125;
&#125;
</code></pre>
<img src="/2022/05/28/java-bing-fa/image-20220528232409607.png" class="asset-class" title="image-20220528232409607">

<h4 id="CyclicBarrier"><a href="#CyclicBarrier" class="headerlink" title="CyclicBarrier"></a>CyclicBarrier</h4><p>任务执行到一定阶段, 等待其他任务对齐(做加号，可再次使用,在子线程await()通过回调判断)</p>
<pre><code class="prettyprint">public CyclicBarrier(int parties, Runnable barrierAction) &#123;&#125;//parties：让多少个线程或者任务等待至barrier状态，barrierAction：parties线程结束的回调
public CyclicBarrier(int parties) &#123;&#125;//parties：让多少个线程或者任务等待至barrier状态
public int await() throws InterruptedException, BrokenBarrierException &#123; &#125;;//来挂起当前线程，直至所有线程都到达barrier状态再同时执行后续任务；
public int await(long timeout, TimeUnit unit)throws InterruptedException,BrokenBarrierException,TimeoutException &#123; &#125;;//这些线程等待至一定的时间，如果还有线程没有到达barrier状态就直接让到达barrier的线程执行后续任务
</code></pre>
<p>代码示例<code>CyclicBarrierDemo</code></p>
<pre><code class="prettyprint">public class CyclicBarrierDemo &#123;
    public static void main(String[] args) throws InterruptedException &#123;
        CyclicBarrier cyclicBarrier = new CyclicBarrier(5, new Runnable() &#123;
            @Override
            public void run() &#123;
                System.out.println(&quot;回调&gt;&gt;&quot;+Thread.currentThread().getName());
                System.out.println(&quot;回调&gt;&gt;线程组执行结束&quot;);
                System.out.println(&quot;==&gt;各个子线程执行结束。。。。&quot;);
            &#125;
        &#125;);
        for (int i = 0; i &lt; 5; i++) &#123;
            new Thread(new readNum(i,cyclicBarrier)).start();
        &#125;
        
        System.out.println(&quot;==&gt;主线程执行结束。。。。&quot;);
        
        //CyclicBarrier 可以重复利用，
        // 这个是CountDownLatch做不到的
//        for (int i = 11; i &lt; 16; i++) &#123;
//            new Thread(new readNum(i,cyclicBarrier)).start();
//        &#125;
    &#125;
    static class readNum  implements Runnable&#123;
        private int id;
        private CyclicBarrier cyc;
        public readNum(int id,CyclicBarrier cyc)&#123;
            this.id = id;
            this.cyc = cyc;
        &#125;
        @Override
        public void run() &#123;
            synchronized (this)&#123;
                System.out.println(&quot;id:&quot;+id+&quot;,&quot;+Thread.currentThread().getName());
                try &#123;
                    cyc.await();
                    System.out.println(&quot;线程组任务&quot; + id + &quot;结束，其他任务继续&quot;);
//                    cyc.await();   // 注意跟CountDownLatch不同，这里在子线程await
                &#125; catch (Exception e) &#123;
                    e.printStackTrace();
                &#125;
            &#125;
        &#125;
    &#125;
&#125;
</code></pre>
<img src="/2022/05/28/java-bing-fa/image-20220528232738351.png" class="asset-class" title="image-20220528232738351">

<p>代码示例<code>CyclicBarrierDemo2</code></p>
<pre><code class="prettyprint">public class CyclicBarrierDemo2 &#123;
    public static void main(String[] args) &#123;
        int N = 4;
        CyclicBarrier barrier  = new CyclicBarrier(N);
        for(int i=0;i&lt;N;i++) &#123;
            new Writer(barrier).start();
        &#125;
        try &#123;
            Thread.sleep(10000);
        &#125; catch (InterruptedException e) &#123;
            e.printStackTrace();
        &#125;
        System.out.println(&quot;====&gt;  CyclicBarrier重用&quot;);
        
        for(int i=0;i&lt;N;i++) &#123;
            new Writer(barrier).start();
        &#125;
    &#125;
    static class Writer extends Thread&#123;
        private CyclicBarrier cyclicBarrier;
        public Writer(CyclicBarrier cyclicBarrier) &#123;
            this.cyclicBarrier = cyclicBarrier;
        &#125;
        @Override
        public void run() &#123;
            System.out.println(&quot;线程&quot;+Thread.currentThread().getName()+&quot;正在写入数据...&quot;);
            try &#123;
                Thread.sleep(3000);      //以睡眠来模拟写入数据操作
                System.out.println(&quot;线程&quot;+Thread.currentThread().getName()+&quot;写入数据完毕，等待其他线程写入完毕&quot;);
                
                cyclicBarrier.await();
            &#125; catch (InterruptedException e) &#123;
                e.printStackTrace();
            &#125;catch(BrokenBarrierException e)&#123;
                e.printStackTrace();
            &#125;
            System.out.println(Thread.currentThread().getName()+&quot;所有线程写入完毕，继续处理其他任务...&quot;);
        &#125;
    &#125;
&#125;
</code></pre>
<img src="/2022/05/28/java-bing-fa/image-20220528232836700.png" class="asset-class" title="image-20220528232836700">

<h4 id="小结"><a href="#小结" class="headerlink" title="小结"></a>小结</h4><img src="/2022/05/28/java-bing-fa/image-20220528232908736.png" class="asset-class" title="image-20220528232908736">

<ul>
<li>CountDownLatch和CyclicBarrier都能够实现线程之间的等待，只不过它们侧重点不同：	<ul>
<li>CountDownLatch一般用于某个线程A等待若干个其他线程执行完任务之后，它才执行；</li>
<li>而CyclicBarrier一般用于一组线程互相等待至某个状态，然后这一组线程再同时执行；</li>
</ul>
</li>
</ul>
<p>　　　　另外，CountDownLatch是不能够重用的，而CyclicBarrier是可以重用的。</p>
<ul>
<li>Semaphore其实和锁有点类似，它一般用于控制对某组资源的访问权限。</li>
</ul>
<h3 id="并发集合类"><a href="#并发集合类" class="headerlink" title="并发集合类"></a>并发集合类</h3><h4 id="List线程安全"><a href="#List线程安全" class="headerlink" title="List线程安全"></a>List线程安全</h4><p>既然线程安全是写冲突和读写冲突导致的 最简单办法就是，读写都加锁</p>
<ul>
<li><p>ArrayList 的方法都加上 synchronized -&gt; Vector</p>
</li>
<li><p>Collections.synchronizedList，强制将 List 的操作加上同步</p>
</li>
<li><p>Arrays.asList，不允许添加删除，但是可以 set 替换元素</p>
</li>
<li><p>Collections.unmodifiableList，不允许修改内容，包括添加删除和 set</p>
</li>
</ul>
<pre><code class="prettyprint">public class SyncListDemo &#123;
    public static void main(String[] args) &#123;
        List list0 = Arrays.asList(1,2,3,4,5,6,7,8,8);
        list0.set(8,9);        // 可以修改内容，不能变动元素数量
        // list0.add(10)  will throw an error
        
        List list = new ArrayList(); // 正常List，可以操作
        list.addAll(list0);
        List list1 = Collections.synchronizedList(list);
        // 多线程操作
        // to do something
        System.out.println(Arrays.toString(list1.toArray()));
        
        Collections.shuffle(list1);
        System.out.println(Arrays.toString(list1.toArray()));
        
        // 假如不再修改
        List list2 = Collections.unmodifiableList(list1);
        System.out.println(list2.getClass());
        
        list2.set(8,10);
        System.out.println(Arrays.toString(list2.toArray()));
        
        list2.add(11);
        System.out.println(Arrays.toString(list2.toArray()));
    &#125; 
&#125;
</code></pre>
<img src="/2022/05/28/java-bing-fa/image-20220528234607137.png" class="asset-class" title="image-20220528234607137">

<h4 id="CopyOnWriteArrayList"><a href="#CopyOnWriteArrayList" class="headerlink" title="CopyOnWriteArrayList"></a>CopyOnWriteArrayList</h4><ul>
<li><p>写加锁，保证不会写混乱</p>
</li>
<li><p>写在一个 Copy 副本上，而不是原始数据上(读写分离，最终一致)</p>
</li>
<li><p><code>add</code> 插入元素时，在新副本操作，不影响旧引用</p>
<pre><code class="prettyprint">public boolean add(E e) &#123;
    final ReentrantLock lock = this.lock;
    lock.lock();
    try &#123;
        Object[] elements = getArray();
        int len = elements.length;
        Object[] newElements = Arrays.copyOf(elements, len + 1);
        newElements[len] = e;
        setArray(newElements);
        return true;
    &#125; finally &#123;
        lock.unlock();
    &#125;
&#125;
</code></pre>
</li>
<li><p><code>remove</code> 删除末尾元素，直接 使用前 N-1 个元素创建 一个新数组；删除其他位置元素， 创建新数组，将剩余元素 复制到新数组</p>
<pre><code class="prettyprint">public E remove(int index) &#123;
    final ReentrantLock lock = this.lock;
    lock.lock();
    try &#123;
        Object[] elements = getArray();
        int len = elements.length;
        E oldValue = get(elements, index);
        int numMoved = len - index - 1;
        if (numMoved == 0)
            setArray(Arrays.copyOf(elements, len - 1));
        else &#123;
            Object[] newElements = new Object[len - 1];
            System.arraycopy(elements, 0, newElements, 0, index);
            System.arraycopy(elements, index + 1, newElements, index,
                             numMoved);
            setArray(newElements);
        &#125;
        return oldValue;
    &#125; finally &#123;
        lock.unlock();
    &#125;
&#125;
</code></pre>
</li>
<li><p><code>get</code> 读取无需加锁</p>
<pre><code class="prettyprint">private E get(Object[] a, int index) &#123;
    return (E) a[index];
&#125;

/**
     * &#123;@inheritDoc&#125;
     *
     * @throws IndexOutOfBoundsException &#123;@inheritDoc&#125;
     */
public E get(int index) &#123;
    return get(getArray(), index);
&#125;
</code></pre>
</li>
<li><p><code>COWIterator</code> 使用迭代器，直接拿当前的数组对象做 一个快照，此后的 List 元素变动，就跟这次迭代 没关系了</p>
<ul>
<li><p>获取迭代器</p>
<pre><code class="prettyprint"> public Iterator&lt;E&gt; iterator() &#123;
     return new COWIterator&lt;E&gt;(getArray(), 0);
 &#125;

/**
     * &#123;@inheritDoc&#125;
     *
     * &lt;p&gt;The returned iterator provides a snapshot of the state of the list
     * when the iterator was constructed. No synchronization is needed while
     * traversing the iterator. The iterator does &lt;em&gt;NOT&lt;/em&gt; support the
     * &#123;@code remove&#125;, &#123;@code set&#125; or &#123;@code add&#125; methods.
     */
public ListIterator&lt;E&gt; listIterator() &#123;
    return new COWIterator&lt;E&gt;(getArray(), 0);
&#125;
</code></pre>
</li>
</ul>
<p><code>COWIterator</code></p>
<pre><code class="prettyprint">static final class COWIterator&lt;E&gt; implements ListIterator&lt;E&gt; &#123;
    /** Snapshot of the array 快照*/
    private final Object[] snapshot; 
    /** Index of element to be returned by subsequent call to next.  */
    private int cursor;

    private COWIterator(Object[] elements, int initialCursor) &#123;
        cursor = initialCursor;
        snapshot = elements;
    &#125;

    public boolean hasNext() &#123;
        return cursor &lt; snapshot.length;
    &#125;

    public boolean hasPrevious() &#123;
        return cursor &gt; 0;
    &#125;

    @SuppressWarnings(&quot;unchecked&quot;)
    public E next() &#123;
        if (! hasNext())
            throw new NoSuchElementException();
        return (E) snapshot[cursor++];
    &#125;

    @SuppressWarnings(&quot;unchecked&quot;)
    public E previous() &#123;
        if (! hasPrevious())
            throw new NoSuchElementException();
        return (E) snapshot[--cursor];
    &#125;

    public int nextIndex() &#123;
        return cursor;
    &#125;

    public int previousIndex() &#123;
        return cursor-1;
    &#125;

    /**
         * Not supported. Always throws UnsupportedOperationException.
         * @throws UnsupportedOperationException always; &#123;@code remove&#125;
         *         is not supported by this iterator.
         */
    public void remove() &#123;
        throw new UnsupportedOperationException();
    &#125;

    /**
         * Not supported. Always throws UnsupportedOperationException.
         * @throws UnsupportedOperationException always; &#123;@code set&#125;
         *         is not supported by this iterator.
         */
    public void set(E e) &#123;
        throw new UnsupportedOperationException();
    &#125;

    /**
         * Not supported. Always throws UnsupportedOperationException.
         * @throws UnsupportedOperationException always; &#123;@code add&#125;
         *         is not supported by this iterator.
         */
    public void add(E e) &#123;
        throw new UnsupportedOperationException();
    &#125;

    @Override
    public void forEachRemaining(Consumer&lt;? super E&gt; action) &#123;
        Objects.requireNonNull(action);
        Object[] elements = snapshot;
        final int size = elements.length;
        for (int i = cursor; i &lt; size; i++) &#123;
            @SuppressWarnings(&quot;unchecked&quot;) E e = (E) elements[i];
            action.accept(e);
        &#125;
        cursor = size;
    &#125;
&#125;
</code></pre>
</li>
</ul>
<h4 id="ConcurrentHashMap"><a href="#ConcurrentHashMap" class="headerlink" title="ConcurrentHashMap"></a>ConcurrentHashMap</h4><h5 id="Java7-分段锁"><a href="#Java7-分段锁" class="headerlink" title="Java7 分段锁"></a>Java7 分段锁</h5><ul>
<li>默认16个Segment，降低锁粒度。 concurrentLevel &#x3D; 16</li>
</ul>
<img src="/2022/05/28/java-bing-fa/image-20220528235452123.png" class="asset-class" title="image-20220528235452123">

<h5 id="Java8-自旋"><a href="#Java8-自旋" class="headerlink" title="Java8-自旋"></a>Java8-自旋</h5><img src="/2022/05/28/java-bing-fa/image-20220528235602891.png" class="asset-class" title="image-20220528235602891">

<pre><code class="prettyprint">public class ConcurrentHashMapDemo &#123;
    
    public static void main(String[] args) &#123;
        demo1();
    &#125;
    public static void demo1() &#123;
        final Map&lt;String, AtomicInteger&gt; count = new ConcurrentHashMap&lt;&gt;();
        final CountDownLatch endLatch = new CountDownLatch(2);
        Runnable task = new Runnable() &#123;
            @Override
            public void run() &#123;
                AtomicInteger oldValue;
                for (int i = 0; i &lt; 5; i++) &#123;
                    oldValue = count.get(&quot;a&quot;);
                    if (null == oldValue) &#123;
                        AtomicInteger zeroValue = new AtomicInteger(0);
                        oldValue = count.putIfAbsent(&quot;a&quot;, zeroValue);
                        if (null == oldValue) &#123;
                            oldValue = zeroValue;
                        &#125;
                    &#125;
                    oldValue.incrementAndGet();
                &#125;
                endLatch.countDown();
            &#125;
        &#125;;
        new Thread(task).start();
        new Thread(task).start();
        try &#123;
            endLatch.await();
            System.out.println(count);
        &#125; catch (Exception e) &#123;
            e.printStackTrace();
        &#125;
    &#125;
&#125;
</code></pre>
<h2 id="ThreadLocal"><a href="#ThreadLocal" class="headerlink" title="ThreadLocal"></a>ThreadLocal</h2><ul>
<li><p>常用方法</p>
<ul>
<li><p><code>public ThreadLocal()</code>构造方法 </p>
</li>
<li><p><code>protected T initialValue()</code> 覆写-设置初始默认值 </p>
</li>
<li><p><code>void set(T value)</code> 设置本线程对应的值 </p>
</li>
<li><p><code>void remove()</code> 清理本线程对应的值 </p>
</li>
<li><p><code>T get()</code> 获取本线程对应的值</p>
</li>
</ul>
</li>
<li><p>使用场景</p>
<ul>
<li>线程本地变量 </li>
<li>场景: 每个线程一个副本 </li>
<li>不改方法签名静默传参 </li>
<li>及时进行清理</li>
</ul>
</li>
<li><p>可以看做是 Context 模式，减少显式传递参数</p>
</li>
</ul>
<pre><code class="prettyprint">public class ThreadLocalDemo &#123;
    
    private static ThreadLocal&lt;Integer&gt; seqNum = new ThreadLocal&lt;Integer&gt;() &#123;
        public Integer initialValue() &#123;
            return 0;
        &#125;
    &#125;;
    public ThreadLocal&lt;Integer&gt; getThreadLocal() &#123;
        return seqNum;
    &#125;
    public int getNextNum() &#123;
        seqNum.set(seqNum.get() + 1);
        return seqNum.get();
    &#125;
    public static void main(String[] args) &#123;
        ThreadLocalDemo threadLocalMain = new ThreadLocalDemo();
    
        SnThread client1 = new SnThread(threadLocalMain);
        SnThread client2 = new SnThread(threadLocalMain);
        SnThread client3 = new SnThread(threadLocalMain);
        
        client1.start();
        client2.start();
        client3.start();
    &#125;
    private static class SnThread extends Thread &#123;
        private ThreadLocalDemo sn;
        public SnThread(ThreadLocalDemo sn) &#123;
            this.sn = sn;
        &#125;
        public void run() &#123;
            for (int i = 0; i &lt; 3; i++) &#123;
                System.out.println(&quot;thread[&quot; + Thread.currentThread().getName() + &quot;] ---&gt; sn [&quot; + sn.getNextNum() + &quot;]&quot;);
            &#125;
            sn.getThreadLocal().remove();
        &#125;
    &#125;
&#125;
</code></pre>
<img src="/2022/05/28/java-bing-fa/image-20220529000224433.png" class="asset-class" title="image-20220529000224433">

<h2 id="并行Stream"><a href="#并行Stream" class="headerlink" title="并行Stream"></a>并行Stream</h2><pre><code class="prettyprint">public class StreamParallelDemo &#123;
    public static void main(String[] args) &#123;
        List&lt;Integer&gt; list = new ArrayList&lt;&gt;();
        IntStream.range(1, 10000).forEach(i -&gt; list.add(i));
        BlockingQueue&lt;Long&gt; blockingQueue = new LinkedBlockingQueue(10000);
        List&lt;Long&gt; longList = list.stream().parallel()
                .map(i -&gt; i.longValue())
                .sorted()
                .collect(Collectors.toList());
//      // 串行，单线程
//      longList.stream().forEach(
        // 并行，默认使用CPU * 2个线程
        longList.stream().parallel().forEach(
                i -&gt; &#123;
            try &#123;
                blockingQueue.put(i);
            &#125; catch (InterruptedException e) &#123;
                e.printStackTrace();
            &#125;
        &#125;);
        System.out.println(&quot;blockingQueue:&quot; + blockingQueue.toString());
    &#125;   
&#125;
</code></pre>

      </section>

      
      
        <nav class="article-nav">
          
            <div class="article-nav-item layout-padding">
  <article class="card-container article-nav-card content-padding--primary soft-size--large soft-style--box">
    
      <div class="card-cover" background-image-lazy data-img="https://api.lixingyong.com/api/images?postid=bb352c2c&type=url&itype=image"></div>
    
    <div class="card-text">
      
        <a href="/2022/06/03/mysql-suo-ji-zhi/" itemprop="url">
          <h2 class="card-text--title text-ellipsis">mysql锁机制</h2>
        </a>
      
      <div class="card-text--row">Newer</div>
    </div>
  </article>
</div>
          
          
            <div class="article-nav-item layout-padding">
  <article class="card-container article-nav-card content-padding--primary soft-size--large soft-style--box">
    
      <div class="card-cover" background-image-lazy data-img="https://api.lixingyong.com/api/images?postid=be09ce71&type=url&itype=image"></div>
    
    <div class="card-text">
      
        <a href="/2022/05/28/prettyprint/" itemprop="url">
          <h2 class="card-text--title text-ellipsis">prettyprint</h2>
        </a>
      
      <div class="card-text--row">Older</div>
    </div>
  </article>
</div>
          
        </nav>
      

      <section class="page-message-container layout-padding">
        


  
  
    <div class="valine-container comments-container content-padding--primary soft-size--large soft-style--box">
      <div id="valine_thread" class="valine-thread"></div>
    </div>
    <script type="text/javascript" src="//cdn1.lncld.net/static/js/3.0.4/av-min.js"></script>
    <script type="text/javascript" src='//unpkg.com/valine/dist/Valine.min.js'></script>
    <script type="text/javascript">
      new Valine({
        el: "#valine_thread",
        appId: "yEts8yIOQopn7imcDAmwhlNi-gzGzoHsz",
        appKey: "nyOyHJdsDGQh3UI0TdNdLLnN",
        avatar: "mm",
        placeholder: "随便说点什么叭～",
        notify: true,
        visitor: true,
        pageSize: 10,
      });
    </script>
  

  
  


      </section>
    </div>
    <div class="widget-info">
      <section class="widget-calendar widget-item layout-margin content-padding--primary soft-size--large soft-style--box">
  <div class="widget-body">
	<div id="calendar"></div>
  </div>
</section>

      <section class="widget-categorys widget-item layout-margin content-padding--primary soft-size--large soft-style--box">
  <div class="widget-title">
    <svg class="icon icon-categories" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M900.3614811 257.09082106h-339.81629553l-67.96326003-101.9448889c-19.41807444-29.12711113-48.54518557-43.69066667-82.52681443-43.69066667H123.6385189c-53.39970333 0-97.09036999 43.69066667-97.09037113 97.09036999v582.54222222c0 53.39970333 43.69066667 97.09036999 97.09037113 97.09037002h776.7229622c53.39970333 0 97.09036999-43.69066667 97.09037113-97.09037002V354.18119104c0-53.39970333-43.69066667-97.09036999-97.09037113-97.09036998z m-97.09036999 242.72592554H220.72888889c-24.27259221 0-48.54518557-24.27259221-48.54518556-48.54518556s24.27259221-48.54518557 48.54518556-48.54518444h582.54222222c24.27259221 0 48.54518557 24.27259221 48.54518556 48.54518444s-24.27259221 48.54518557-48.54518556 48.54518556z" fill="currentColor"></path>
</svg>
    <span>CATEGORYS</span>
  </div>
  <div class="widget-body">
    <ul class="categorys-list">
      
        <li class="categorys-list-item">
          <a href="/categories/%E6%8A%80%E6%9C%AF/">
            技术 (11)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E7%AE%97%E6%B3%95/">
            算法 (15)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E5%B7%A5%E5%85%B7/">
            工具 (3)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E9%97%AE%E9%A2%98/">
            问题 (8)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E8%BD%AF%E4%BB%B6/">
            软件 (31)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E4%B8%AD%E9%97%B4%E4%BB%B6/">
            中间件 (26)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E5%90%8E%E7%AB%AF/">
            后端 (1)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/java/">
            java (4)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E6%95%B0%E6%8D%AE/">
            数据 (5)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/linux/">
            linux (3)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/web/">
            web (1)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E7%89%9B%E8%B7%AF%E6%9D%91/">
            牛路村 (1)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E9%97%B2%E8%B0%88/">
            闲谈 (5)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E5%89%8D%E7%AB%AF/">
            前端 (1)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E5%BE%AE%E4%BF%A1/">
            微信 (1)
          </a>
        </li>
      
        <li class="categorys-list-item">
          <a href="/categories/%E8%8B%A5%E4%BE%9D/">
            若依 (1)
          </a>
        </li>
      
    </ul>
  </div>
</section>

      <section class="widget-tags widget-item  layout-margin content-padding--primary soft-size--large soft-style--box">
  <div class="widget-title">
    <svg class="icon icon-tags" viewBox="0 0 1098 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M283.42180005 272q0-28.38857157-20.09142843-48.48000001t-48.47999998-20.09142842-48.48000002 20.09142842-20.09142846 48.48000001 20.09142846 48.48 48.48000002 20.09142843 48.47999998-20.09142843 20.09142843-48.48zM855.0332285 580.57142843q0 28.38857157-19.81714313 48.2057147l-263.03999997 263.58857157q-20.9142853 19.81714313-48.75428534 19.81714312-28.38857157 0-48.20571468-19.81714312l-383.04-383.58857157q-20.36571468-19.81714313-34.55999999-54.10285688t-14.19428534-62.6742853l0-222.85714313q0-27.84000002 20.36571469-48.20571469t48.2057147-20.36571466l222.85714313 0q28.38857157 0 62.6742853 14.19428529t54.65142842 34.55999999l383.04000001 382.49142843q19.81714313 20.9142853 19.81714314 48.75428532zM1060.74751475 580.57142843q0 28.38857157-19.81714313 48.2057147l-263.04 263.58857157q-20.9142853 19.81714313-48.75428531 19.81714312-19.26857155 0-31.61142843-7.47428531t-28.38857159-24.13714314l251.79428534-251.7942853q19.81714313-19.81714313 19.81714308-48.20571469 0-27.84000002-19.81714308-48.75428531l-383.04000001-382.49142845q-20.36571468-20.36571468-54.65142842-34.55999999t-62.67428532-14.19428534l120 0q28.38857157 0 62.67428532 14.19428534t54.65142842 34.55999999l383.03999998 382.49142845q19.81714313 20.9142853 19.81714314 48.75428531z" fill="currentColor"></path>
</svg>
    <span>TAGS</span>
  </div>
  <div class="widget-body">
    <div class="tags-cloud">
      <a href="/tags/crontab/" style="font-size: 10px;" class="tags-cloud-0">crontab</a> <a href="/tags/docker/" style="font-size: 20px;" class="tags-cloud-10">docker</a> <a href="/tags/elasticsearch/" style="font-size: 10px;" class="tags-cloud-0">elasticsearch</a> <a href="/tags/fastdfs/" style="font-size: 10px;" class="tags-cloud-0">fastdfs</a> <a href="/tags/git/" style="font-size: 10px;" class="tags-cloud-0">git</a> <a href="/tags/go/" style="font-size: 12.5px;" class="tags-cloud-3">go</a> <a href="/tags/hexo/" style="font-size: 10px;" class="tags-cloud-0">hexo</a> <a href="/tags/idea/" style="font-size: 10px;" class="tags-cloud-0">idea</a> <a href="/tags/jvm/" style="font-size: 11.25px;" class="tags-cloud-1">jvm</a> <a href="/tags/kafka/" style="font-size: 11.25px;" class="tags-cloud-1">kafka</a> <a href="/tags/linux/" style="font-size: 15px;" class="tags-cloud-5">linux</a> <a href="/tags/maven/" style="font-size: 10px;" class="tags-cloud-0">maven</a> <a href="/tags/minio/" style="font-size: 11.25px;" class="tags-cloud-1">minio</a> <a href="/tags/mysql/" style="font-size: 13.75px;" class="tags-cloud-4">mysql</a> <a href="/tags/nginx/" style="font-size: 12.5px;" class="tags-cloud-3">nginx</a> <a href="/tags/node/" style="font-size: 10px;" class="tags-cloud-0">node</a> <a href="/tags/oracle/" style="font-size: 10px;" class="tags-cloud-0">oracle</a> <a href="/tags/pulsar/" style="font-size: 10px;" class="tags-cloud-0">pulsar</a> <a href="/tags/rabbitmq/" style="font-size: 17.5px;" class="tags-cloud-8">rabbitmq</a> <a href="/tags/redis/" style="font-size: 16.25px;" class="tags-cloud-6">redis</a> <a href="/tags/redis-%E4%BA%8B%E5%8A%A1/" style="font-size: 10px;" class="tags-cloud-0">redis,事务</a> <a href="/tags/rocketmq/" style="font-size: 17.5px;" class="tags-cloud-8">rocketmq</a> <a href="/tags/shell/" style="font-size: 10px;" class="tags-cloud-0">shell</a> <a href="/tags/spring/" style="font-size: 10px;" class="tags-cloud-0">spring</a> <a href="/tags/tomcat/" style="font-size: 10px;" class="tags-cloud-0">tomcat</a> <a href="/tags/vim/" style="font-size: 10px;" class="tags-cloud-0">vim</a> <a href="/tags/yml/" style="font-size: 10px;" class="tags-cloud-0">yml</a> <a href="/tags/zookeeper/" style="font-size: 10px;" class="tags-cloud-0">zookeeper</a> <a href="/tags/%E4%B8%87%E5%B9%B4%E5%8F%B0/" style="font-size: 10px;" class="tags-cloud-0">万年台</a> <a href="/tags/%E4%B8%AD%E9%97%B4%E4%BB%B6/" style="font-size: 18.75px;" class="tags-cloud-9">中间件</a> <a href="/tags/%E4%BA%8B%E5%8A%A1/" style="font-size: 10px;" class="tags-cloud-0">事务</a> <a href="/tags/%E5%8A%A0%E5%AF%86/" style="font-size: 13.75px;" class="tags-cloud-4">加密</a> <a href="/tags/%E5%93%A8%E5%85%B5/" style="font-size: 10px;" class="tags-cloud-0">哨兵</a> <a href="/tags/%E5%B7%A5%E5%85%B7/" style="font-size: 11.25px;" class="tags-cloud-1">工具</a> <a href="/tags/%E5%B8%B8%E7%94%A8%E7%AE%97%E6%B3%95/" style="font-size: 16.25px;" class="tags-cloud-6">常用算法</a> <a href="/tags/%E5%B9%B6%E5%8F%91/" style="font-size: 10px;" class="tags-cloud-0">并发</a> <a href="/tags/%E6%96%87%E4%BB%B6%E5%AD%98%E5%82%A8/" style="font-size: 11.25px;" class="tags-cloud-1">文件存储</a> <a href="/tags/%E7%B4%A2%E5%BC%95/" style="font-size: 10px;" class="tags-cloud-0">索引</a> <a href="/tags/%E9%94%81%E6%9C%BA%E5%88%B6/" style="font-size: 10px;" class="tags-cloud-0">锁机制</a> <a href="/tags/%E9%97%AE%E9%A2%98/" style="font-size: 10px;" class="tags-cloud-0">问题</a>
    </div>
  </div>
</section>
    </div>
  </article>
</div>
<script>
	//解决中文转义无法跳转锚点问题
	var blog = document.querySelector("#blog-content");
	var content = blog.innerHTML;
	var regExp2 = /<h([1-6]) id=\"(\S*?)\">/g;
	var	data = content.replace(regExp2, function(word,i){
		var ws = word.split("\"");
			return ws[0]+"\""+encodeURIComponent(ws[1])+"\""+ws[2];
		},"g");
	blog.innerHTML = data;
</script>

    <!-- footer container -->
<footer id="footer" class="footer">
  <div class="footer-container">
    
    <div class="social-icons">
      
        
          <a href="https://music.163.com/#/user/home?id=444731906" class="soft-size--primary soft-style--box" target="_blank" rel="noopener noreferrer">
            <svg class="icon icon-<%= icon %>" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <path d="M952.17867 503.263237a341.054956 341.054956 0 0 0-56.853199-113.706399 408.604266 408.604266 0 0 0-109.723463-98.352823 304.662484 304.662484 0 0 0-143.257215-42.077792L621.305897 170.238394a40.343287 40.343287 0 0 1 10.792472-36.392472 56.88532 56.88532 0 0 1 36.392472-18.758344 102.785445 102.785445 0 0 1 56.853199 18.758344c6.263488 3.404768 10.792472 9.090088 17.05596 13.073024a57.335006 57.335006 0 0 0 82.999247-70.632873 66.521455 66.521455 0 0 0-22.74128-27.848432 237.691343 237.691343 0 0 0-89.262735-43.202007A170.559598 170.559598 0 0 0 625.288833 6.42409a167.026349 167.026349 0 0 0-60.836135 37.516688 164.328231 164.328231 0 0 0-40.921456 51.713927 156.908407 156.908407 0 0 0-8.54404 113.706399l13.651192 52.870264a284.298118 284.298118 0 0 0-158.064743 109.209535 256.963614 256.963614 0 0 0-43.202007 156.908407 248.419573 248.419573 0 0 0 13.651192 74.487327 205.281807 205.281807 0 0 0 80.718695 104.616312 185.945295 185.945295 0 0 0 136.447679 25.696361 193.879046 193.879046 0 0 0 156.330238-196.705646L708.802008 503.263237c-11.948808-46.060728-24.443664-91.543287-35.814304-137.025847a182.283563 182.283563 0 0 1 47.763112 18.180176 316.611292 316.611292 0 0 1 47.763111 34.690088A239.907654 239.907654 0 0 1 840.752823 529.987453a284.169636 284.169636 0 0 1 0 158.064743 252.241907 252.241907 0 0 1-21.584943 51.167879 308.741782 308.741782 0 0 1-168.279047 144.542033 387.918695 387.918695 0 0 1-130.184191 23.319448 332.607277 332.607277 0 0 1-155.206022-37.516688A367.233124 367.233124 0 0 1 194.87478 672.666499a373.014806 373.014806 0 0 1-20.460727-180.806022A366.173149 366.173149 0 0 1 406.869762 198.536512a57.399247 57.399247 0 0 0 13.073023-100.055207 76.189711 76.189711 0 0 0-63.662735-3.404768A479.815307 479.815307 0 0 0 68.705646 436.163614a488.905395 488.905395 0 0 0 129.027855 450.84266 454.857716 454.857716 0 0 0 248.997741 131.886574 470.885822 470.885822 0 0 0 138.117942 0A454.889837 454.889837 0 0 0 773.042911 952.949561a427.523212 427.523212 0 0 0 170.559598-209.232622 417.276788 417.276788 0 0 0 22.74128-109.209536 378.089837 378.089837 0 0 0-14.165119-131.244166z m-412.747804 118.845671a72.174655 72.174655 0 0 1-56.8532-10.792471 98.352823 98.352823 0 0 1-37.516687-61.382184 170.68808 170.68808 0 0 1 0-65.943287 133.042911 133.042911 0 0 1 33.533751-63.662735 181.35207 181.35207 0 0 1 80.718695-46.606776l39.219072 148.364367a204.189711 204.189711 0 0 1 5.107152 26.146048 79.594479 79.594479 0 0 1-64.208783 73.844918z"></path>
  </svg>
          </a>
        
      
        
          <a href="https://www.zhihu.com" class="soft-size--primary soft-style--box" target="_blank" rel="noopener noreferrer">
            <svg t="1587373160860" class="icon icon-zhihu" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M544.949 561.422s0-71.387-34.779-75.050c-34.779-3.663-142.775 0-142.775 0v-219.654h161.078s-1.83-73.219-32.949-73.219h-261.755l43.93-117.148s-65.897 3.663-89.692 45.761-98.844 252.604-98.844 252.604 25.627 10.983 67.726-20.134c42.101-31.116 56.743-86.033 56.743-86.033l76.879-3.663 1.83 223.316s-133.621-1.83-161.078 0c-27.457 1.83-42.101 75.050-42.101 75.050h203.182s-18.307 124.47-69.557 214.164c-53.085 89.692-151.929 161.078-151.929 161.078s71.387 29.287 140.947-10.983c69.557-42.101 120.811-223.316 120.811-223.316l162.912 203.182s14.643-97.013-1.83-124.47c-18.307-27.457-113.49-137.283-113.49-137.283l-42.101 36.607 29.287-120.811h177.552zM587.050 188.010l-1.83 660.793h65.897l23.795 82.37 115.321-82.37h162.912v-660.793h-366.091zM879.92 775.584h-76.879l-97.013 75.050-21.965-75.050h-20.134v-512.527h215.991v512.527z"></path>
</svg>
          </a>
        
      
        
          <a href="https://gitee.com/RocPengHua" class="soft-size--primary soft-style--box" target="_blank" rel="noopener noreferrer">
            <svg class="icon icon-<%= icon %>" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
    <path d="M512 1024C229.248 1024 0 794.752 0 512S229.248 0 512 0s512 229.248 512 512-229.248 512-512 512z m259.168-568.896h-290.752a25.28 25.28 0 0 0-25.28 25.28l-0.032 63.232c0 13.952 11.296 25.28 25.28 25.28h177.024a25.28 25.28 0 0 1 25.28 25.28v12.64a75.84 75.84 0 0 1-75.84 75.84h-240.224a25.28 25.28 0 0 1-25.28-25.28v-240.192a75.84 75.84 0 0 1 75.84-75.84h353.92a25.28 25.28 0 0 0 25.28-25.28l0.064-63.2a25.312 25.312 0 0 0-25.28-25.312H417.184a189.632 189.632 0 0 0-189.632 189.6v353.952c0 13.952 11.328 25.28 25.28 25.28h372.928a170.656 170.656 0 0 0 170.656-170.656v-145.376a25.28 25.28 0 0 0-25.28-25.28z" p-id="1954"></path>
  </svg>
          </a>
        
      
        
          <a href="https://github.com/RocPengHua" class="soft-size--primary soft-style--box" target="_blank" rel="noopener noreferrer">
            <svg class="icon icon-github" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M64.6 512c0 195.6 125.4 361.9 300.1 422.9 23.5 5.9 19.9-10.8 19.9-22.2v-77.6c-135.8 15.9-141.3-74-150.5-89-18.5-31.5-61.9-39.5-49-54.5 31-15.9 62.5 4 98.9 58 26.4 39.1 77.9 32.5 104.1 26 5.7-23.5 17.9-44.5 34.7-60.9-140.7-25.2-199.4-111.1-199.4-213.3 0-49.5 16.4-95.1 48.4-131.8-20.4-60.6 1.9-112.4 4.9-120.1 58.2-5.2 118.5 41.6 123.3 45.3 33.1-8.9 70.8-13.7 112.9-13.7 42.4 0 80.3 4.9 113.5 13.9 11.3-8.6 67.3-48.8 121.4-43.9 2.9 7.7 24.7 58.3 5.5 118.1 32.5 36.8 49 82.8 49 132.4 0 102.3-59 188.3-200.2 213.2 23.5 23.3 38.1 55.5 38.1 91.1v112.7c0.8 9 0 17.9 15.1 17.9C832.7 877 960.4 709.4 960.4 512.1c0-247.5-200.6-447.9-447.9-447.9C265 64.1 64.6 264.5 64.6 512z"></path>
</svg>
          </a>
        
      
        
          <a href="https://twitter.com/guanquanhong" class="soft-size--primary soft-style--box" target="_blank" rel="noopener noreferrer">
            <svg class="icon icon-twitter" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
  <path d="M962.285714 233.142857q-38.285714 56-92.571429 95.428571 0.571429 8 0.571429 24 0 74.285714-21.714286 148.285714t-66 142-105.428571 120.285714-147.428571 83.428571-184.571429 31.142857q-154.857143 0-283.428571-82.857143 20 2.285714 44.571429 2.285714 128.571429 0 229.142857-78.857143-60-1.142857-107.428571-36.857143t-65.142857-91.142857q18.857143 2.857143 34.857143 2.857143 24.571429 0 48.571429-6.285714-64-13.142857-106-63.714286t-42-117.428571l0-2.285714q38.857143 21.714286 83.428571 23.428571-37.714286-25.142857-60-65.714286t-22.285714-88q0-50.285714 25.142857-93.142857 69.142857 85.142857 168.285714 136.285714t212.285714 56.857143q-4.571429-21.714286-4.571429-42.285714 0-76.571429 54-130.571429t130.571429-54q80 0 134.857143 58.285714 62.285714-12 117.142857-44.571429-21.142857 65.714286-81.142857 101.714286 53.142857-5.714286 106.285714-28.571429z"></path>
</svg>
          </a>
        
      
    </div>
     
    <p>&copy; 2024 <a href="/" target="_blank">RocPengHua</a></p>

    

    <p>Powered by <a href="https://hexo.io" target="_blank" rel="noopener noreferrer">Hexo</a> Theme - <a href="https://github.com/miiiku/flex-block" target="_blank" rel="noopener noreferrer author">flex-block</a></p>

    <p>
      <a href="javascript:;" id="theme-light">🌞 浅色</a>
      <a href="javascript:;" id="theme-dark">🌛 深色</a>
      <a href="javascript:;" id="theme-auto">🤖️ 自动</a>
    </p>
  </div>
</footer>
  </div>

  <div class="back-to-top-fixed soft-size--round soft-style--box">
    <svg class="icon icon-back-to-top" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg">
      <path d="M725.333333 426.666667c-12.8 0-21.333333-4.266667-29.866667-12.8l-213.333333-213.333333c-17.066667-17.066667-17.066667-42.666667 0-59.733333s42.666667-17.066667 59.733333 0l213.333333 213.333333c17.066667 17.066667 17.066667 42.666667 0 59.733333C746.666667 422.4 738.133333 426.666667 725.333333 426.666667z"></path>
      <path d="M298.666667 426.666667c-12.8 0-21.333333-4.266667-29.866667-12.8-17.066667-17.066667-17.066667-42.666667 0-59.733333l213.333333-213.333333c17.066667-17.066667 42.666667-17.066667 59.733333 0s17.066667 42.666667 0 59.733333l-213.333333 213.333333C320 422.4 311.466667 426.666667 298.666667 426.666667z"></path>
      <path d="M512 896c-25.6 0-42.666667-17.066667-42.666667-42.666667L469.333333 170.666667c0-25.6 17.066667-42.666667 42.666667-42.666667s42.666667 17.066667 42.666667 42.666667l0 682.666667C554.666667 878.933333 537.6 896 512 896z"></path>
    </svg>
  </div>

  
  <!-- aplayer -->


<!-- dplayer -->




  


  


  <!-- Baidu Analytics START -->
  <script>
    var _hmt = _hmt || [];
    (function () {
      if (window.location.hostname === "localhost" || window.location.hostname.startsWith("192.168")) {
        return console.log("本地调试");
      }
      var hm = document.createElement("script");
      hm.src = "https://hm.baidu.com/hm.js?true";
      var s = document.getElementsByTagName("script")[0];
      s.parentNode.insertBefore(hm, s);
    })();
  </script>
  <!-- Baidu Analytics End -->

  




<script src="/js/script.js"></script>


  
  <link rel="stylesheet" href="/lib/aplayer/APlayer.min.css">
<script type="text/javascript" src="/lib/aplayer/APlayer.min.js"></script>
<script type="text/javascript" src="https://code.jquery.com/jquery-3.5.1.min.js"></script>
<script src="/js/search.js"></script>

<!-- Calendar -->

    <script src="/js/calendar.js"></script>
    <script src="/js/languages.js"></script>
    <script type="text/javascript">
        $(function() {
            $('#calendar').aCalendar(
                'zh-CN',
                {single:false, root:'calendar/'}
            );
        });
    </script>

<!-- 尾部用户自定义相关内容 -->
<div id="aplayer"></div>
<script type="text/javascript">

	/*获取音乐*/
	$.get("https://api.i-meto.com/meting/api?server=netease&type=playlist&id=3778678&r=0.37201068616290645", function(result){
		if(result && result.code  == 50000){
			console.log(result.msg);
			return;
		}
	    const ap = new APlayer({
	    container: document.getElementById('aplayer'),
	    global:true,
	    id:'3778678',
	    server: 'netease',
	    type: 'paylist',
	    fixed: true,
	    preload: 'none',
	    theme: '#ffa500',
	    autoplay: false,
	    audio: result
	  });
	});










	/*图片放大js*/
	function createImgEventFullScreen() {
        var imgs = $(".post-container").find("img");
        for (var i = 0; i < imgs.length; i++) {
            // $(imgs[i]).click(createCover(imgs[i]));
            imgs[i].onclick = function (e) {
                var src = e.srcElement.currentSrc;
                var _this = $(this);
                console.log(_this);
                createCover(src,_this);
            }
        }
        function createCover(src,_this) {
            console.log(_this);
            console.log(src);
            var cover = $("<div id='outerDiv'  style='position:fixed;top:0;left:0;background:rgba(0,0,0,0.7);z-index:5;width:100%;height:100%;display:none;'><div id='innerDiv' style='position:absolute;'><img  id='bigImg' style='border:5px solid #fff;' src=''/></div></div>");
            $("#outerDiv").remove();
            $("body").append(cover);
            imgShow("#outerDiv", "#innerDiv", "#bigImg", _this,src);

        }
    }
    function imgShow(outerDiv, innerDiv, bigImg, _this,src) {
        //var src = _this.attr("src"); //获取当前点击的common-img元素中的src属性
        $(bigImg).attr("src", src); //设置#bigImg元素的src属性

        /*获取当前点击图片的真实大小，并显示弹出层及大图*/
        $("<img/>").attr("src", src).on('load',function () {
            var windowW = $(window).width(); //获取当前窗口宽度
            var windowH = $(window).height(); //获取当前窗口高度
            var realWidth = this.width; //获取图片真实宽度
            var realHeight = this.height; //获取图片真实高度
            var imgWidth, imgHeight;
            var scale = 0.8; //缩放尺寸，当图片真实宽度和高度大于窗口宽度和高度时进行缩放

            if (realHeight > windowH * scale) { //判断图片高度
                imgHeight = windowH * scale; //如大于窗口高度，图片高度进行缩放
                imgWidth = imgHeight / realHeight * realWidth; //等比例缩放宽度
                if (imgWidth > windowW * scale) { //如宽度仍大于窗口宽度
                    imgWidth = windowW * scale; //再对宽度进行缩放
                }
            } else if (realWidth > windowW * scale) { //如图片高度合适，判断图片宽度
                imgWidth = windowW * scale; //如大于窗口宽度，图片宽度进行缩放
                imgHeight = imgWidth / realWidth * realHeight; //等比例缩放高度
            } else { //如果图片真实高度和宽度都符合要求，高宽不变
                imgWidth = realWidth;
                imgHeight = realHeight;
            }
            $(bigImg).css("width", imgWidth); //以最终的宽度对图片缩放

            var w = (windowW - imgWidth) / 2; //计算图片与窗口左边距
            var h = (windowH - imgHeight) / 2; //计算图片与窗口上边距
            $(innerDiv).css({ "top": h, "left": w }); //设置#innerDiv的top和left属性
            //console.log('****')
            $(outerDiv).fadeIn("fast"); //淡入显示#outerDiv
        });

        $(outerDiv).click(function () { //再次点击淡出消失弹出层
            $(this).fadeOut("fast");
        });
    }
    setTimeout(function () {
        createImgEventFullScreen();
    }, 1000)
</script>
<style>
.aplayer.aplayer-fixed.aplayer-narrow .aplayer-body{
	width: 0px!important
}
.aplayer.aplayer-narrow .aplayer-body, .aplayer.aplayer-narrow .aplayer-pic {
	width: 0px!important
}
</style>
</body>
</html>